Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Cmd+Option+I. Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Cmd+Shift+Enter.

Read in dependencies

library(ggplot2)
package ‘ggplot2’ was built under R version 3.6.2
library(treeio)
Registered S3 method overwritten by 'treeio':
  method     from
  root.phylo ape 
library(ggtree)
ggtree v2.5.0.991  For help: https://yulab-smu.top/treedata-book/

If you use ggtree in published research, please cite the most appropriate paper(s):

- Guangchuang Yu. Using ggtree to visualize data on tree-like structures. Current Protocols in Bioinformatics, 2020, 69:e96. doi:10.1002/cpbi.96
- Guangchuang Yu, Tommy Tsan-Yuk Lam, Huachen Zhu, Yi Guan. Two methods for mapping and visualizing associated data on phylogeny using ggtree. Molecular Biology and Evolution 2018, 35(12):3041-3043. doi:10.1093/molbev/msy194
- Guangchuang Yu, David Smith, Huachen Zhu, Yi Guan, Tommy Tsan-Yuk Lam. ggtree: an R package for visualization and annotation of phylogenetic trees with their covariates and other associated data. Methods in Ecology and Evolution 2017, 8(1):28-36. doi:10.1111/2041-210X.12628
library(ggnewscale)
package ‘ggnewscale’ was built under R version 3.6.2
library(plyr)
library(dplyr)
package ‘dplyr’ was built under R version 3.6.2
Attaching package: ‘dplyr’

The following objects are masked from ‘package:plyr’:

    arrange, count, desc, failwith, id, mutate, rename, summarise, summarize

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
── Attaching packages ─────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.3.0 ──
✓ tibble  3.0.3     ✓ purrr   0.3.4
✓ tidyr   1.1.0     ✓ stringr 1.4.0
✓ readr   1.3.1     ✓ forcats 0.5.0
package ‘tibble’ was built under R version 3.6.2package ‘tidyr’ was built under R version 3.6.2package ‘purrr’ was built under R version 3.6.2── Conflicts ────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::arrange()   masks plyr::arrange()
x purrr::compact()   masks plyr::compact()
x dplyr::count()     masks plyr::count()
x tidyr::expand()    masks ggtree::expand()
x dplyr::failwith()  masks plyr::failwith()
x dplyr::filter()    masks stats::filter()
x dplyr::id()        masks plyr::id()
x dplyr::lag()       masks stats::lag()
x dplyr::mutate()    masks plyr::mutate()
x dplyr::rename()    masks plyr::rename()
x dplyr::summarise() masks plyr::summarise()
x dplyr::summarize() masks plyr::summarize()
library(phytools)
package ‘phytools’ was built under R version 3.6.2Loading required package: ape
package ‘ape’ was built under R version 3.6.2
Attaching package: ‘ape’

The following object is masked from ‘package:ggtree’:

    rotate

The following object is masked from ‘package:treeio’:

    drop.tip

Loading required package: maps

Attaching package: ‘maps’

The following object is masked from ‘package:purrr’:

    map

The following object is masked from ‘package:plyr’:

    ozone


Attaching package: ‘phytools’

The following object is masked from ‘package:treeio’:

    read.newick
library(randomcoloR)
library(RColorBrewer)
library(lubridate)
package ‘lubridate’ was built under R version 3.6.2
Attaching package: ‘lubridate’

The following objects are masked from ‘package:base’:

    date, intersect, setdiff, union
library(readxl)
library(ggforce)
package ‘ggforce’ was built under R version 3.6.2
library(ggstance)
package ‘ggstance’ was built under R version 3.6.2
Attaching package: ‘ggstance’

The following objects are masked from ‘package:ggplot2’:

    geom_errorbarh, GeomErrorbarh
library(ggridges)
package ‘ggridges’ was built under R version 3.6.2
library(Cairo)
package ‘Cairo’ was built under R version 3.6.2
library(cowplot)

********************************************************
Note: As of version 1.0.0, cowplot does not change the
  default ggplot2 theme anymore. To recover the previous
  behavior, execute:
  theme_set(theme_cowplot())
********************************************************


Attaching package: ‘cowplot’

The following object is masked from ‘package:lubridate’:

    stamp
library(ggmap)
Google's Terms of Service: https://cloud.google.com/maps-platform/terms/.
Please cite ggmap if you use it! See citation("ggmap") for details.

Attaching package: ‘ggmap’

The following object is masked from ‘package:cowplot’:

    theme_nothing

The following objects are masked from ‘package:ggtree’:

    inset, theme_inset
library(CoordinateCleaner)
package ‘CoordinateCleaner’ was built under R version 3.6.2Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     
library(gridExtra)

Attaching package: ‘gridExtra’

The following object is masked from ‘package:dplyr’:

    combine
library(hexbin)
library(emojifont)
library(scales)
package ‘scales’ was built under R version 3.6.2
Attaching package: ‘scales’

The following object is masked from ‘package:purrr’:

    discard

The following object is masked from ‘package:readr’:

    col_factor
library(pairsnp)
library(rPinecone)
replacing previous import ‘ape::ring’ by ‘igraph::ring’ when loading ‘rPinecone’replacing previous import ‘ape::mst’ by ‘igraph::mst’ when loading ‘rPinecone’replacing previous import ‘ape::edges’ by ‘igraph::edges’ when loading ‘rPinecone’replacing previous import ‘BMhyd::AICc’ by ‘phangorn::AICc’ when loading ‘rPinecone’replacing previous import ‘igraph::diversity’ by ‘phangorn::diversity’ when loading ‘rPinecone’
R.Version()
$platform
[1] "x86_64-apple-darwin15.6.0"

$arch
[1] "x86_64"

$os
[1] "darwin15.6.0"

$system
[1] "x86_64, darwin15.6.0"

$status
[1] ""

$major
[1] "3"

$minor
[1] "6.0"

$year
[1] "2019"

$month
[1] "04"

$day
[1] "26"

$`svn rev`
[1] "76424"

$language
[1] "R"

$version.string
[1] "R version 3.6.0 (2019-04-26)"

$nickname
[1] "Planting of a Tree"
print(sessionInfo())
R version 3.6.0 (2019-04-26)
Platform: x86_64-apple-darwin15.6.0 (64-bit)
Running under: macOS High Sierra 10.13.6

Matrix products: default
BLAS:   /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/3.6/Resources/lib/libRlapack.dylib

locale:
[1] en_GB.UTF-8/en_GB.UTF-8/en_GB.UTF-8/C/en_GB.UTF-8/en_GB.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] rPinecone_0.1.0          pairsnp_0.1.0            scales_1.1.1             emojifont_0.5.3          hexbin_1.28.1           
 [6] gridExtra_2.3            CoordinateCleaner_2.0-17 ggmap_3.0.0              cowplot_1.0.0            Cairo_1.5-12.2          
[11] ggridges_0.5.3           ggstance_0.3.5           ggforce_0.3.2            readxl_1.3.1             lubridate_1.7.9         
[16] RColorBrewer_1.1-2       randomcoloR_1.1.0.1      phytools_0.7-47          maps_3.3.0               ape_5.4-1               
[21] forcats_0.5.0            stringr_1.4.0            purrr_0.3.4              readr_1.3.1              tidyr_1.1.0             
[26] tibble_3.0.3             tidyverse_1.3.0          dplyr_1.0.0              plyr_1.8.6               ggnewscale_0.4.5        
[31] ggtree_2.5.0.991         treeio_1.9.1             ggplot2_3.3.3           

loaded via a namespace (and not attached):
  [1] uuid_0.1-4              backports_1.1.8         BMhyd_1.2-8             fastmatch_1.1-0         igraph_1.2.5           
  [6] lazyeval_0.2.2          sp_1.4-2                rncl_0.8.4              digest_0.6.25           fansi_0.4.1            
 [11] magrittr_1.5            geoaxe_0.1.0            cluster_2.0.8           modelr_0.1.8            sysfonts_0.8.1         
 [16] prettyunits_1.1.1       jpeg_0.1-8.1            colorspace_1.4-1        blob_1.2.1              rvest_0.3.6            
 [21] haven_2.3.1             xfun_0.16               rgdal_1.5-16            crayon_1.3.4            jsonlite_1.7.0         
 [26] phylobase_0.8.10        phangorn_2.5.5          glue_1.4.1              polyclip_1.10-0         gtable_0.3.0           
 [31] geiger_2.0.7            V8_3.2.0                mvtnorm_1.1-1           oai_0.3.0               DBI_1.1.0              
 [36] Rcpp_1.0.5              showtextdb_3.0          plotrix_3.7-8           progress_1.2.2          units_0.6-7            
 [41] tidytree_0.3.3          subplex_1.6             deSolve_1.28            rgbif_3.3.0             animation_2.6          
 [46] httr_1.4.2              geosphere_1.5-10        ellipsis_0.3.1          XML_3.99-0.3            pkgconfig_2.0.3        
 [51] farver_2.0.3            dbplyr_1.4.4            conditionz_0.1.0        reshape2_1.4.4          tidyselect_1.1.0       
 [56] rlang_0.4.7             munsell_0.5.0           cellranger_1.1.0        tools_3.6.0             cli_2.0.2              
 [61] generics_0.0.2          ade4_1.7-15             broom_0.7.0             knitr_1.29              fs_1.4.2               
 [66] RgoogleMaps_1.4.5.3     showtext_0.9            nlme_3.1-139            whisker_0.4             aplot_0.0.6            
 [71] xml2_1.3.2              compiler_3.6.0          rstudioapi_0.11         curl_4.3                png_0.1-7              
 [76] e1071_1.7-3             reprex_0.3.0            clusterGeneration_1.3.4 tweenr_1.0.1            RNeXML_2.4.5           
 [81] stringi_1.4.6           rgeos_0.5-5             lattice_0.20-38         Matrix_1.2-17           classInt_0.4-3         
 [86] vctrs_0.3.2             pillar_1.4.6            lifecycle_0.2.0         BiocManager_1.30.10     combinat_0.0-8         
 [91] corpcor_1.6.9           data.table_1.12.8       bitops_1.0-6            raster_3.3-13           patchwork_1.0.1        
 [96] R6_2.4.1                KernSmooth_2.23-15      TreeSim_2.4             codetools_0.2-16        MASS_7.3-51.4          
[101] gtools_3.8.2            assertthat_0.2.1        proto_1.0.0             rjson_0.2.20            withr_2.2.0            
[106] rnaturalearth_0.1.0     mnormt_1.5-6            expm_0.999-5            parallel_3.6.0          hms_0.5.3              
[111] quadprog_1.5-8          grid_3.6.0              coda_0.19-3             class_7.3-15            rvcheck_0.1.8          
[116] Rtsne_0.15              sf_0.9-5                numDeriv_2016.8-1.1     scatterplot3d_0.3-41   

Read in data


# ML Tree (using raw sequences with minimal filters)
TPA.rawseq.ML.tree.file <- "TPA-uber.remasked.2020-11-10.lowcov75.SNPs.aln.renamed.treefile"

# ML tree (refined dataset)
TPA.MLtree.file <- "TPA-uber.remasked.2020-11-10.goodcov25.gubbins.SNPs.aln.renamed.treefile"

# Pyjar tree (refined dataset)
TPA.pyjar.file <- "TPA-uber.remasked.2020-11-10.goodcov25.gubbins.SNPs.aln.renamed.pyjar.tre"

# Multiple Sequence alignment of SNPs for ML tree/pyjar
TPA.MSA.SNPs.aln.file <- "TPA-uber.remasked.2020-11-10.goodcov25.gubbins.SNPs.renamed.aln"

# Pinecone clustering bootstrap data
pinecone.10.file <- "TPA-uber.bootstrapped-pinecone.10-3.2021-01-27.v2.pinecone.bootstrap.table.csv"

# Master Metadata spreadsheet
#TPA.meta1.file <- "/Users/mb29/Treponema/Expanded_Global_Sequencing/Global_Sequence_Collection_Info_update-03-2021.xlsx"
TPA.meta1.file <- "Supplementary_Data1_Sample-Metadata__03-2021.xlsx"


# Some population prevalence data
UK.stats.file <- "PHE_2019_UK_Syphilis-rate-per-100k-pop__02-11-2020.tsv"
BC.stats.file <- "BCCDC-Canada__BC-Syphilis-rate-per-100k-pop_2017___02-11-2020.tsv"

# BEAST Analyses
# Subsampled BEAST analysis 1
TPA.beast.subtree.file <- "TPA-uber.remasked.2020-11-10.gubbins.subsampled.2020-11-18.WGS.rendates.noInv_StrictCSkyline_combined.2020-11-23.consensus.tree"

beast.subtree.skyline.file <- "TPA-uber.remasked.2020-11-10.gubbins.subsampled.2020-11-18.WGS.rendates.noInv_StrictCSkyline_1.export_skyline_data.txt"

beast.subtree.skyline.lineage.file <- "TPA-uber_beast2_strict-skyline-500M_10pop_combined.lineages-data.tsv"


# Subsampled BEAST analysis 2 (repeat)
repeat.subsampled.skyline.tree.file <- "TPA-uber.remasked.2020-11-10.gubbins.subsampled.2.2020-11-23.WGS.rendates.noInv.Strict-Skyline-HKY_combined.2020-11-26.consensus.tree"

repeat.subsampled.skyline.data.file <- "TPA-uber.remasked.2020-11-10.gubbins.subsampled.2.2020-11-23.WGS.rendates.noInv.Strict-Skyline-HKY_1.skyline-data.tsv"
repeat.subsampled.skyline.lineages.data.file <- "TPA-uber.remasked.2020-11-10.gubbins.subsampled.2.2020-11-23.WGS.rendates.noInv.Strict-Skyline-HKY_1.skyline-lineages-data.tsv"

# Full size BEAST2 analysis
full.beast2.tree.file <- "TPA-uber_beast2_strict-skyline-500M_10pop_consensus.tree"

beast2.runs.filepath <- "./"

beast2.full.skyline.path <- "TPA-uber_beast2_strict-skyline-500M_10pop_combined.skyline-data.tsv"
beast2.full.lineages.path <- "TPA-uber_beast2_strict-skyline-500M_10pop_combined.lineages-data.tsv"
beast2.full.popdistro.path <- "TPA-uber_beast2_strict-skyline-500M_10pop_combined.pop-distributions_p100.txt"


beast2.pop.decline.file <- "TPA-uber_beast2_strict-skyline-500M_10pop_pop-decline.1990-2015.p50_population_change_distribution.csv"


beast2.pop.increase.file  <- "TPA-uber_beast2_strict-skyline-500M_10pop_pop-increase.1990-2015.p100_population_change_distribution.csv"

pop.decline.supporting.trees.file <- "TPA-uber_beast2_strict-skyline-500M_10pop_pop-decline.1990-2015.p50_trees_supporting.nex"

pop.decline.notsupporting.trees.file <- "TPA-uber_beast2_strict-skyline-500M_10pop_pop-decline.1990-2015.p50_trees_not_supporting.nex"


# Sublineage BEAST analysis
sublineage.skylines.filepath <- "./"
pop.distro.path <- "./" 
pop.distro.sublin.1.file <- "TPA-uber.remasked.2020-11-10.goodcov25.gubbins.WGS.sublineage.new.1.noinv.Strict-Skyline_combined.pop-expansion"
pop.distro.sublin.2.file <- "TPA-uber.remasked.2020-11-10.goodcov25.gubbins.WGS.sublineage.new.2.noinv.Strict-Skyline_combined.pop-expansion"
pop.distro.sublin.8.file <- "TPA-uber.remasked.2020-11-10.goodcov25.gubbins.WGS.sublineage.new.8.noinv.Strict-Skyline_combined.pop-expansion"

# Recombination analysis
recombination_event.file <- "Supplementary_Table_Recombination-Events_2021-03-25.xlsx"

# Tip Date Randomisation
random.tip.summary.file <- "clockRate.stats.csv"

# Macrolide resistance allele calls
TPA.global.compmapping.23s.file <-"competitive-mapping_combined-reports.all.2020-12-01.final.tsv"

# Pinecone assignments
pinecone.clusters.MLoriginal.file <- "Global-TPA.goodcov.rPinecone10-3.assignments_2020-11-11.csv"

WGS.site.positions.file <- "TPA-uber.remasked.2020-11-10.goodcov25.gubbins.SNPs.site-positions.txt"

# Location to save files to
Figure_output_directory <- "/Users/mb29/Papers/Global_Treponema_Uber-Paper_2020/Figures/Figure_Drafting/"

Read in trees

TPA.rawseq.ML.tree <- midpoint.root(read.tree(TPA.rawseq.ML.tree.file))
TPA.MLtree <- midpoint.root(read.tree(TPA.MLtree.file))
TPA.pyjar.tree <- midpoint.root(read.tree(TPA.pyjar.file))

make some shortcuts for plotting

y.theme.strip <- theme(axis.title.y = element_blank(), axis.text.y = element_blank(), axis.ticks.y= element_blank())
y.theme.strip.partial <- theme(axis.text.y = element_blank(), axis.ticks.y= element_blank())

x.theme.strip <- theme(axis.title.x = element_blank(), axis.text.x = element_blank(), axis.ticks.x= element_blank())
x.theme.strip.partial <- theme(axis.text.x = element_blank(), axis.ticks.x= element_blank())
x.theme.strip.labs <- theme(axis.text.x = element_blank(),axis.title.x = element_blank())

x.theme.axis.rotate <- theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))

theme.text.size <- theme(text = element_text(size = 10))

'%notin%' <- Negate('%in%')

Filter metadata

# First do some cleaning
#TPA.meta1 <- readxl::read_excel(TPA.meta1.file,sheet="All_useable_T.pal_01-2020_refil")
TPA.meta1 <- readxl::read_excel(TPA.meta1.file,sheet="Supplementary_Data1_Sample-Meta")
TPA.meta1 <- subset(TPA.meta1, select=-c(A2058G,A2059G,TPA.pinecone.sublineage))


TPA.meta1.2 <- TPA.meta1[TPA.meta1$Sample_Name %in% TPA.rawseq.ML.tree$tip.label,]

TPA.meta1.2 <- TPA.meta1.2[TPA.meta1.2$Species=="TPA",]
#TPA.meta1.2 <- TPA.meta1.2[TPA.meta1.2$Study_Type=="TPA-Global",]
TPA.meta1.2 <- TPA.meta1.2[TPA.meta1.2$Duplicate!="Yes",]
#TPA.meta1.2 <- TPA.meta1.2[TPA.meta1.2$Sample_Year!="-",]


#TPA.meta1.2 <- TPA.meta1.2[TPA.meta1.2$`SKA_Alignment_terrible>50%?`=="No",]
TPA.meta1.2 <- TPA.meta1.2[!is.na(TPA.meta1.2$Sample_Name),]
#TPA.meta1.2 <- data.frame(TPA.meta1.2,stringsAsFactors = F)


TPA.meta1.2$Geo_Country <- gsub("\\_","\\ ",TPA.meta1.2$Geo_Country)

do some date parsing to create date groups

floor_5years  <- function(value){ return(value - value %% 5) }
ceiling_5years <- function(value){ return(round_to_5years(value)+5) }
round_to_5years <- function(value){ return(round(value / 5) * 5) }

TPA.meta1.2$Sample_5year.floor <- floor_5years(as.numeric(TPA.meta1.2$Sample_Year))
NAs introduced by coercion
TPA.meta1.2$Sample_5year.window <- paste0(floor_5years(as.numeric(TPA.meta1.2$Sample_Year)),"-",floor_5years(as.numeric(TPA.meta1.2$Sample_Year))+5)
NAs introduced by coercionNAs introduced by coercion
# Some samples have uncertain dates (up to 20-30 years uncertainty), but for the purposes of these plotting categories we'll use the centrepoint year
TPA.meta1.2$Sample_5year.window <- sapply(1:nrow(TPA.meta1.2), function(x) ifelse(TPA.meta1.2$Sample_Year[x]=="-",NA, ifelse(is.na(TPA.meta1.2$Sample_5year.window[x]),NA, ifelse(TPA.meta1.2$Sample_Year[x]=="1950-1980","1965-1970",ifelse(TPA.meta1.2$Sample_Year[x]=="1960-1980","1965-1970" ,ifelse(TPA.meta1.2$Sample_Year[x]=="1980-1999","1985-1990",TPA.meta1.2$Sample_5year.window[x]))))))

#TPA.meta1.2[TPA.meta1.2$Sample_5year.window=="NA-NA","Sample_5year.window"] <- NA

#View(TPA.meta1.2[,c("Sample_Name","Sample_Year","Sample_5year.window")])


# Make colour scheme for date window
TPA.5year.window.brewcols <- data.frame(window.5year=unique(TPA.meta1.2$Sample_5year.window), stringsAsFactors=F)
TPA.5year.window.brewcols$window.5year <- TPA.5year.window.brewcols[order(TPA.5year.window.brewcols$window.5year),]
TPA.5year.window.brewcols$window.5year <- factor(TPA.5year.window.brewcols$window.5year, levels=TPA.5year.window.brewcols$window.5year)
# set colour scale
TPA.5year.window.brewcols$window.5year.cols <- c("Black",brewer.pal(n=11,"RdYlBu"),"white")

#c("1910-1915","1950-1955","1965-1970,"1970-1975","1975-1980","1980-1985","1985-1990","1990-1995","2000-2005","2005-2010","2010-2015","2015-2020","NA")


# Also create a numeric date year for some calculations
TPA.meta1.2$Sample_Year.num <- as.numeric((ifelse(TPA.meta1.2$Sample_Year=="1950-1980","1965",ifelse(TPA.meta1.2$Sample_Year=="1960-1980","1970",TPA.meta1.2$Sample_Year))))
NAs introduced by coercion

Create a colour scheme for countries and continents

# Colouring for country
continental.country.cols.brew2 <- unique(TPA.meta1.2[,c("Geo_Country","Continent")])
continental.country.cols.brew2 <- continental.country.cols.brew2[order(continental.country.cols.brew2$Continent,continental.country.cols.brew2$Geo_Country),]

continental.country.cols.brew2$country.col <- c("#ec7014","#fec44f","#de2d26","#fb6a4a","#bdbdbd","#737373",brewer.pal(n=8,"Purples")[3:8],brewer.pal(n=8,"Blues")[3:8],brewer.pal(n=5,"Greens")[3:5],"#c51b8a","#8c510a")

# Colouring for Continent
continental.cols.brew2 <- data.frame(Continent=sort(unique(TPA.meta1.2$Continent)),stringsAsFactors=F)
continental.cols.brew2$continent.col <- c("#fec44f","#de2d26","#bdbdbd","#2171b5","#74c476","#c51b8a","#ec7014")

# Colouring for TPA Lineage
TPA_Lineage.cols <- data.frame(Lineage=sort(unique(TPA.meta1.2$TPA_Lineage)),stringsAsFactors=F)
#TPA_Lineage.cols$Lineage.col <- c("royalblue2", "grey40", "indianred1")
TPA_Lineage.cols$Lineage.col <- c("royalblue2", "indianred1")
#c("#436eee", "#666666","#ff6a6a")
TPA_Lineage.cols$Lineage <- factor(TPA_Lineage.cols$Lineage, levels=c("Nichols","SS14","outlier"))
#TPA_Lineage.cols$Lineage <- factor(TPA_Lineage.cols$Lineage, levels=c("Nichols","SS14"))


# Lineage Hexcodes
# royalblue2 #436eee
# indianred1 #ff6a6a


#TPA_Lineage.cols[order(TPA_Lineage.cols$Lineage,c("Nichols","SS14","outlier")),]

check labelling issues

TPA.rawseq.ML.tree$tip.label[TPA.rawseq.ML.tree$tip.label %notin% TPA.meta1.2$Sample_Name]
character(0)
TPA.meta1.2$Sample_Name[TPA.meta1.2$Sample_Name %notin% TPA.rawseq.ML.tree$tip.label]
character(0)
# There is one very low coverage sample (TPA_BCC144, 47% genome breadth, 7.9X mean coverage) with odd phylogenetic placement - it's SS14, but basal in this analysis. Since the coverage is so low, it's not possible to further investigate this, so classify it here as SS14.
TPA.meta1.2[(TPA.meta1.2$TPA_Lineage=="outlier"),"TPA_Lineage"] <- "SS14"
# Prepare tree
TPA.rawseq.ML.ggtree <- ggtree(TPA.rawseq.ML.tree,layout = "fan",open.angle = 20, right=T)
Scale for 'y' is already present. Adding another scale for 'y', which will replace the existing scale.
TPA.rawseq.ML.ggtree <- ggtree(TPA.rawseq.ML.tree,layout = "fan",open.angle = 15, right=T)
Scale for 'y' is already present. Adding another scale for 'y', which will replace the existing scale.
# Prepare country dataset
TPA.rawseq.countries.p <- data.frame(row.names=TPA.meta1.2$Sample_Name, Country=TPA.meta1.2$Geo_Country, stringsAsFactors = F)

# Prepare continent dataset
TPA.rawseq.continents.p <- data.frame(row.names=TPA.meta1.2$Sample_Name, Continent=TPA.meta1.2$Continent, stringsAsFactors = F)

# Prepare Major lineage dataset
TPA.rawseq.Lineage.p <- data.frame(row.names=TPA.meta1.2$Sample_Name, Lineage=TPA.meta1.2$TPA_Lineage, stringsAsFactors = F)
TPA.rawseq.ML.ggtree.tippoints <- TPA.rawseq.ML.ggtree %<+% data.frame(Sample_Name=rownames(TPA.rawseq.continents.p), Continent=TPA.rawseq.continents.p$Continent, stringsAsFactors = F) + 
  geom_tippoint(aes(color=Continent), size=0.5, alpha=0.5) + 
  scale_color_manual(name="Continent",values=continental.cols.brew2$continent.col, breaks=continental.cols.brew2$Continent) 

# Rescale colours
TPA.rawseq.ML.ggtree.tippoints <- TPA.rawseq.ML.ggtree.tippoints + new_scale_color()

# Plot continent strip
p.TPA.rawseq.ML.ggtree.tippoint.country.cont <- gheatmap(TPA.rawseq.ML.ggtree.tippoints,TPA.rawseq.continents.p, color=NULL,width=0.075,colnames_angle=-45,colnames_offset_y=0.02, hjust=0.0,font.size=2.25) + 
  scale_fill_manual(name="Continent",values=continental.cols.brew2$continent.col, breaks=continental.cols.brew2$Continent) + 
  theme.text.size + theme(legend.key.size = unit(0.65,"line"),legend.position='right') +
  NULL
Scale for 'fill' is already present. Adding another scale for 'fill', which will replace the existing scale.
p.TPA.rawseq.ML.ggtree.tippoint.country.cont <- p.TPA.rawseq.ML.ggtree.tippoint.country.cont + new_scale_fill()



p.TPA.rawseq.ML.ggtree.tippoint.country.cont <- gheatmap(p.TPA.rawseq.ML.ggtree.tippoint.country.cont,TPA.rawseq.countries.p, color=NULL,width=0.075,offset=0.00001225, colnames_angle=-45,colnames_offset_y=0.02, hjust=0.0,font.size=2.25) + 
  scale_fill_manual(name="Country",values=continental.country.cols.brew2$country.col, breaks=continental.country.cols.brew2$Geo_Country) +
  theme.text.size + theme(legend.key.size = unit(0.65,"line"),legend.position='right') +
  NULL
Scale for 'fill' is already present. Adding another scale for 'fill', which will replace the existing scale.
p.TPA.rawseq.ML.ggtree.tippoint.country.cont <- p.TPA.rawseq.ML.ggtree.tippoint.country.cont + new_scale_fill()


# Add sublineage
p.TPA.rawseq.ML.ggtree.tippoint.country.cont <- gheatmap(p.TPA.rawseq.ML.ggtree.tippoint.country.cont,TPA.rawseq.Lineage.p, color=NULL,width=0.075,offset=0.00002425, colnames_angle=-45,colnames_offset_y=0.02, hjust=-0.0,font.size=2.25) + 
  scale_fill_manual(name="Lineage",values=TPA_Lineage.cols$Lineage.col, breaks=TPA_Lineage.cols$Lineage) +
  theme.text.size + theme(legend.key.size = unit(0.65,"line"),legend.position='right') +
  NULL
Scale for 'fill' is already present. Adding another scale for 'fill', which will replace the existing scale.
p.TPA.rawseq.ML.ggtree.tippoint.country.cont <- p.TPA.rawseq.ML.ggtree.tippoint.country.cont + new_scale_fill()

# Plot tree
#p.TPA.rawseq.ML.ggtree.tippoint.country.cont

#Cairo::Cairo(file=paste0(Figure_output_directory, "Supplementary_Figure1_Global-TPA.low-cov-MLtree_02-20.svg"), width = 1000, height = 1000,type="svg",units = "pt")
p.TPA.rawseq.ML.ggtree.tippoint.country.cont

#dev.off()
TPA.rawseq.country.counts <- TPA.meta1.2[TPA.meta1.2$Sample_Year!="-",] %>% dplyr::group_by(Sample_Year, Geo_Country) %>% 
  dplyr::summarise(Count=n())

TPA.rawseq.country.counts$Sample_Year <- ifelse(TPA.rawseq.country.counts$Sample_Year=="1960-1980","1970",TPA.rawseq.country.counts$Sample_Year)

TPA.rawseq.country.counts <- plyr::join(data.frame(Sample_Year=c(1912:2019),stringsAsFactors=F), TPA.rawseq.country.counts)
TPA.rawseq.country.counts <- TPA.rawseq.country.counts[!is.na(TPA.rawseq.country.counts$Geo_Country),]
TPA.rawseq.country.counts$Geo_Country <- factor(TPA.rawseq.country.counts$Geo_Country, levels=continental.country.cols.brew2$Geo_Country)


p.Country.temporal.bubbleplot <- ggplot(TPA.rawseq.country.counts, aes(Sample_Year, Geo_Country, colour=Geo_Country)) +
  geom_point(alpha=0.65, aes(size=Count)) + 
  #guides(colour=FALSE) +
  theme_light() +
  scale_size_area(max_size = 8,breaks=c(1,5,10,25,50,75,100)) +
  scale_color_manual(name="Country",values=continental.country.cols.brew2$country.col, breaks=continental.country.cols.brew2$Geo_Country) +
  theme.text.size + theme(legend.key.size = unit(0.65,"line"),legend.position='none') +
  coord_cartesian(xlim=c(1950,2020)) +
  labs(y="Country", x="Sample Year")
#p.Country.temporal.bubbleplot

p.Country.temporal.bubbleplot.legend <- get_legend(p.Country.temporal.bubbleplot + theme(legend.key.size = unit(0.65,"line"),legend.position='left'))
raw.country.counts <- TPA.meta1.2 %>% group_by(Geo_Country) %>% summarise(Count=n())
`summarise()` ungrouping output (override with `.groups` argument)
raw.country.counts$Geo_Country <- factor(raw.country.counts$Geo_Country,levels=continental.country.cols.brew2$Geo_Country)

p.Country.hbarplot <- ggplot(raw.country.counts, aes(Count,Geo_Country,fill=Geo_Country)) +
  geom_barh(stat="identity", position="stack", width=0.75) +
  theme_light() +
  theme.text.size + theme(legend.key.size = unit(0.65,"line"),legend.position='none') +
  scale_fill_manual(name="Country",values=continental.country.cols.brew2$country.col, breaks=continental.country.cols.brew2$Geo_Country) +
  geom_text(data=raw.country.counts, aes((Count+30), Geo_Country,label=Count), size=2.5, inherit.aes = F) +
  labs(y="Country", x="Samples/Country") +
  coord_cartesian(xlim=c(0,625))
#p.Country.hbarplot  

plot together

grid.arrange(p.Country.temporal.bubbleplot, p.Country.hbarplot + y.theme.strip, ncol=2, widths=c(3,1))

Now, lets think about just what lineages are where

major.lineage.country.summary.simple <- TPA.meta1.2[TPA.meta1.2$TPA_Lineage %in% c("SS14","Nichols"),] %>% dplyr::group_by(TPA_Lineage,Geo_Country) %>% 
  dplyr::summarise(total.samples=n())
`summarise()` regrouping output by 'TPA_Lineage' (override with `.groups` argument)
major.lineage.country.summary.simple$Geo_Country <- factor(major.lineage.country.summary.simple$Geo_Country, levels=rev(sort(unique(major.lineage.country.summary.simple$Geo_Country)))) 

country.summary.simple <- TPA.meta1.2[TPA.meta1.2$TPA_Lineage %in% c("SS14","Nichols"),] %>% dplyr::group_by(Geo_Country) %>% 
  dplyr::summarise(total.samples=n())
`summarise()` ungrouping output (override with `.groups` argument)
country.summary.simple$Geo_Country <- factor(country.summary.simple$Geo_Country, levels=rev(sort(unique(country.summary.simple$Geo_Country)))) 
major.lineage.country.summary.simple$TPA_Lineage <- factor(major.lineage.country.summary.simple$TPA_Lineage, levels=unique(major.lineage.country.summary.simple$TPA_Lineage))

p.majorlineage.country.props <- ggplot(major.lineage.country.summary.simple, aes(Geo_Country, total.samples, fill=TPA_Lineage)) +
  geom_bar(stat="identity",position = position_fill(reverse = TRUE)) +
  theme_light() + 
  scale_fill_manual(values=c("royalblue2","indianred1")) + 
  scale_y_continuous(breaks=c(0,0.5,1)) +
  coord_flip() +
  theme.text.size +
  labs(y="Proportion", x="Country")
p.majorlineage.country.counts <- ggplot(major.lineage.country.summary.simple, aes(Geo_Country, total.samples, fill=TPA_Lineage)) + 
         geom_bar(stat="identity",position="stack") +
  theme_light() + 
  scale_fill_manual(values=c("royalblue2","indianred1")) +
  #scale_y_log10() +
  coord_flip() +
  labs(fill="TPA Lineage", y="Sample Count") + 
  geom_text(data=country.summary.simple, aes(Geo_Country, (total.samples+22), label=total.samples), size=2.5, inherit.aes = F) +
  theme.text.size
#p.majorlineage.country.counts
major.lineage.country.summary.simple2 <- major.lineage.country.summary.simple
major.lineage.country.summary.simple2$Geo_Country <- factor(major.lineage.country.summary.simple2$Geo_Country,levels=continental.country.cols.brew2$Geo_Country) 

p.majorlineage.country.props.reordered <- ggplot(major.lineage.country.summary.simple2, aes(Geo_Country, total.samples, fill=TPA_Lineage)) + 
  #geom_bar(stat="identity",position="fill", width=0.75) +
  geom_bar(stat="identity",position = position_fill(reverse=TRUE), width=0.75) +
  
  theme_light() + 
  scale_fill_manual(values=TPA_Lineage.cols$Lineage.col, breaks=TPA_Lineage.cols$Lineage) + 
  scale_y_continuous(breaks=c(0,0.5,1)) +
  coord_flip() +
  theme.text.size +
  labs(y="Lineage Proportion", x="Country", fill="TPA Lineage")
#p.majorlineage.country.props.reordered
#grid.arrange(p.Country.temporal.bubbleplot, p.Country.hbarplot + y.theme.strip,p.majorlineage.country.props.reordered + y.theme.strip + theme.text.size + theme(legend.key.size = unit(0.75,"line")), ncol=3, widths=c(6,2,2))

Major lineage bubbleplot timeline


TPA.majorlineage.counts <- TPA.meta1.2[(TPA.meta1.2$Sample_Year!="-" & TPA.meta1.2$TPA_Lineage!="outlier"),] %>% dplyr::group_by(Sample_Year,TPA_Lineage) %>% 
  dplyr::summarise(Count=n())

TPA.majorlineage.counts$Sample_Year <- ifelse(TPA.majorlineage.counts$Sample_Year=="1960-1980","1970",TPA.majorlineage.counts$Sample_Year)

TPA.majorlineage.counts <- plyr::join(data.frame(Sample_Year=c(1912:2019),stringsAsFactors=F), TPA.majorlineage.counts)
TPA.majorlineage.counts <- TPA.majorlineage.counts[!is.na(TPA.majorlineage.counts$TPA_Lineage),]
TPA.majorlineage.counts$TPA_Lineage <- factor(TPA.majorlineage.counts$TPA_Lineage, levels=rev(TPA_Lineage.cols$Lineage))


p.majorlineage.temporal.bubbleplot <- ggplot(TPA.majorlineage.counts, aes(Sample_Year, TPA_Lineage, colour=TPA_Lineage)) +
  geom_point(alpha=0.65, aes(size=Count)) + 
  theme_light() +
  scale_size_area(max_size = 8,breaks=c(1,5,10,25,50,75,100)) +
  #scale_color_manual(name="Country",values=continental.country.cols.brew2$country.col, breaks=continental.country.cols.brew2$Geo_Country) +
  scale_color_manual(name="Lineage",values=TPA_Lineage.cols$Lineage.col, breaks=TPA_Lineage.cols$Lineage) +
  theme.text.size + theme(legend.key.size = unit(0.65,"line"),legend.position='none') +
  coord_cartesian(xlim=c(1950,2020)) +
  labs(y="Lineage", x="Sample Year")
p.majorlineage.temporal.bubbleplot


p.majorlineage.temporal.bubbleplot.legend <- get_legend(p.majorlineage.temporal.bubbleplot + theme(legend.key.size = unit(0.65,"line"),legend.position='left') + guides(size=FALSE))



# total counts
#TPA.majorlineage.counts.simple <- TPA.meta1.2[(TPA.meta1.2$Sample_Year!="-" & TPA.meta1.2$TPA_Lineage!="outlier"),] %>% dplyr::group_by(TPA_Lineage) %>% 
#  dplyr::summarise(Count=n())
TPA.majorlineage.counts.simple <- TPA.meta1.2 %>% dplyr::group_by(TPA_Lineage) %>% 
  dplyr::summarise(Count=n())



p.majorlineage.total.hbarplot <- ggplot(TPA.majorlineage.counts, aes(Count,TPA_Lineage, fill=TPA_Lineage)) +
  geom_barh(stat="identity", position="stack", width=0.65) + 
  theme_light() +
  scale_fill_manual(name="Lineage",values=TPA_Lineage.cols$Lineage.col, breaks=TPA_Lineage.cols$Lineage) +
  geom_text(data=TPA.majorlineage.counts.simple, aes((Count+30), TPA_Lineage, label=Count), size=2.5, inherit.aes = F) +
  theme.text.size + theme(legend.key.size = unit(0.65,"line"),legend.position='none') +
  labs(y="Lineage", x="Count") + 
  coord_cartesian(xlim=c(0,625))
p.majorlineage.total.hbarplot

Look at sample dates and whether a sample was passaged or not

TPA.meta1.2$Sample_Year.2000era <- ifelse(TPA.meta1.2$Sample_Year.num<2000,"pre2000","post1999")
TPA.meta1.2[TPA.meta1.2$Sample_Name=="DAL-1","Sample_Year.2000era"] <- "pre2000"


# Proportion of samples before and after 2000
TPA.meta1.2[!is.na(TPA.meta1.2$Sample_Year.2000era),] %>% dplyr::group_by(Sample_Year.2000era) %>%
  dplyr::summarise(count=n()) %>% 
  dplyr::mutate(perc=(count/sum(count)*100))
`summarise()` ungrouping output (override with `.groups` argument)
# Proportion of clinicals before 2000
data.frame(TPA.meta1.2[(!is.na(TPA.meta1.2$Sample_Year.2000era) & TPA.meta1.2$Sample_Year.2000era=="pre2000"),] %>% dplyr::group_by(Direct_from_clin) %>%
               dplyr::summarise(count=n()) %>% 
               dplyr::mutate(perc=(count/sum(count)*100)),stringsAsFactors = F)
`summarise()` ungrouping output (override with `.groups` argument)
# Proportion of clinicals after 1999
data.frame(TPA.meta1.2[(!is.na(TPA.meta1.2$Sample_Year.2000era) & TPA.meta1.2$Sample_Year.2000era=="post1999"),] %>% dplyr::group_by(Direct_from_clin) %>%
               dplyr::summarise(count=n()) %>% 
               dplyr::mutate(perc=(count/sum(count)*100)),stringsAsFactors = F)
`summarise()` ungrouping output (override with `.groups` argument)

Do a map of sample distributions


#country.coords.subset1 <- data.frame(Geo_Country=unique(sublineage.country.summary.simple$Geo_Country))
country.coords.subset <- data.frame(Geo_Country=raw.country.counts$Geo_Country, stringsAsFactors = F)

country.coords.subset$name <- gsub("Czech Republic","Czechia",gsub("USA","United States",gsub("UK","United Kingdom",gsub("\\_","\\ ",country.coords.subset$Geo_Country))))

# Russia is very large - let's centre on Tuva instead (but keep the labelling for database consistency)
country.coords.subset$name <- gsub("Russia", "Tuva", country.coords.subset$name)

# Merge with published centroid locations and deduplicate
country.coords.subset <- plyr::join(country.coords.subset,CoordinateCleaner::countryref,by="name")

# Mexico centre's oddly - take the location of Mexico City instead
country.coords.subset[country.coords.subset$Geo_Country=="Mexico","centroid.lon"] <- country.coords.subset[country.coords.subset$Geo_Country=="Mexico","capital.lon"]
country.coords.subset[country.coords.subset$Geo_Country=="Mexico","centroid.lat"] <- country.coords.subset[country.coords.subset$Geo_Country=="Mexico","capital.lat"]

country.coords.subset <- country.coords.subset[!duplicated(country.coords.subset$name),c("Geo_Country","name","centroid.lon","centroid.lat")]

# Merge with country sample counts
country.coords.subset.counts <- plyr::join(country.coords.subset,raw.country.counts,by="Geo_Country")


# ggmap
world.gps.bounds <- c(left=-120, bottom=-45, right= 150, top= 72)
stamanmap.global1 <- ggmap::get_stamenmap(bbox=world.gps.bounds, maptype = "toner-lite", zoom=3)

# Reduce the intensity of the basemap (third of the alpha)
stamanmap.global1.attribs <- attributes(stamanmap.global1)
stamanmap.global1.transparent <- matrix(adjustcolor(stamanmap.global1, alpha.f = 0.5),nrow=nrow(stamanmap.global1))
attributes(stamanmap.global1.transparent) <- stamanmap.global1.attribs 


# Plot map with country sampling
stamanmap.global1.p <- ggmap(stamanmap.global1.transparent)
stamanmap.global1.p <- stamanmap.global1.p + 
  #geom_point(data=country.coords.subset.counts, aes(centroid.lon, centroid.lat, size=Count+0.5),alpha=0.50, show.legend = F) + 
  geom_point(data=country.coords.subset.counts, aes(centroid.lon, centroid.lat, size=Count, color=Geo_Country),alpha=0.8) +
  guides(colour=FALSE) +
  theme_light() +
  theme(legend.key.size = unit(0.65,"line"),legend.position='right', ) + guides(fill=guide_legend(ncol=3)) +
  theme.text.size +
  scale_color_manual(values=continental.country.cols.brew2$country.col,breaks=continental.country.cols.brew2$Geo_Country) +
  #scale_size_area(max_size = 12,breaks=c(1,5,10,25,50,100,200,400)) +
  #scale_size_binned(breaks=c(1,5,10,25,50,100,200,400)) +
  scale_size_binned(range = c(2, 10),breaks=c(5,20,50,100,200,400)) +
  labs(y="Latitude", x="Longitude", color="Country", size="Sample\nCount")



#Cairo::Cairo(file=paste0(Figure_output_directory, "Global-TPA.low-cov__Map-of-Country-distributions11-2020.svg"), width = 800, height = 500,type="svg",units = "pt")
stamanmap.global1.p

#dev.off()

#stamanmap.global1.p

Plot all together as a combined panel grid

p.bubble.legends.grid <- plot_grid(p.majorlineage.temporal.bubbleplot.legend, p.Country.temporal.bubbleplot.legend, ncol=1, rel_heights=c(1,3))

first_row_country.dist <- plot_grid(stamanmap.global1.p,labels=c('A'),ncol=1,label_size = 11,vjust=-0.25)

row2.3_column_1_country.dist <- plot_grid(p.Country.temporal.bubbleplot, p.majorlineage.temporal.bubbleplot, ncol=1, rel_heights=c(4,1), align=T, labels=c('B','E'),label_size = 11,vjust=-0.25)

row2.3_column_2_country.dist <- plot_grid(p.Country.hbarplot + y.theme.strip + coord_cartesian(x=c(0,620)), p.majorlineage.total.hbarplot + theme(legend.position="none") + y.theme.strip + theme.text.size + coord_cartesian(x=c(0,620)) + labs(x="Samples/Lineage"),ncol=1, rel_heights=c(4,1), align=T, labels=c('C','F'),label_size = 11,vjust=-0.25)

row2.3_column_3_country.dist <- plot_grid(p.majorlineage.country.props.reordered + y.theme.strip + theme.text.size + theme(legend.position="none"), NULL, ncol=1, rel_heights=c(4,1),labels=c('D',''),label_size = 11,vjust=-0.25)

row2.3_combine.columns_country.dist <- plot_grid(row2.3_column_1_country.dist, row2.3_column_2_country.dist, row2.3_column_3_country.dist,p.bubble.legends.grid,rel_widths=c(5,2,1,2), ncol=4)

gg_all_country.dist.complex <- plot_grid(first_row_country.dist, row2.3_combine.columns_country.dist, labels=c('', ''), ncol=1, rel_heights = c(6,5), scale=0.95)

#gg_all_country.dist.complex

#Cairo::Cairo(file=paste0(Figure_output_directory, "Figure1__Country-distros_complex_02-2021.svg"), width = 1000, height = 800,type="svg",units = "pt")
gg_all_country.dist.complex

#dev.off()

Now move onto detailed gubbins masked phylogeny and sublineage analysis

#TPA.MLtree
#TPA.pyjar.tree

#ggtree(TPA.MLtree)
#ggtree(TPA.pyjar.tree)

# Extract SNP distances from pyjar tree
edge.TPAgubbins <- data.frame(TPA.pyjar.tree$edge, edge_num=1:length(TPA.pyjar.tree$edge.length),stringsAsFactors = F)
colnames(edge.TPAgubbins)=c("parent", "node", "edge_num")
edge.TPAgubbins$SNPs <- TPA.pyjar.tree$edge.length

# now build tree
TPA.pyjar.treeplot <- ggtree(TPA.pyjar.tree) %<+% 
  edge.TPAgubbins + geom_text(aes(x=branch, label=SNPs, vjust=-.5),size=3,color="grey50") +
  #geom_tiplab(size=2,align=T,offset=.0001) +
  NULL
TPA.pyjar.treeplot 

Do some clustering using rPinecone (takes a long time, so write out to file and reimport)

#TPA.pyjar.tree.phylo <- as.phylo(TPA.pyjar.tree)
#pinecone.output <- rPinecone::pinecone(TPA.pyjar.tree.phylo,10,3) # standard approach used for TPA

######################## testing ########################
#pinecone.output.8.3 <- rPinecone::pinecone(TPA.pyjar.tree.phylo,8,3) # modifying to see the effect 8.3
#pinecone.output.12.3 <- rPinecone::pinecone(TPA.pyjar.tree.phylo,12,3) # modifying to see the effect 12.3
#pinecone.output <- pinecone.output.12.3
######################## testing ########################

#pinecone.clusters <- data.frame(pinecone.output$table,stringsAsFactors = T)
#pinecone.clusters$Sub.lineage.sing <- gsub("Singleton\\_.+","Singleton",pinecone.clusters$Sub.lineage,perl=T)
#write.csv(pinecone.clusters, file=paste0(Figure_output_directory, "Global-TPA.goodcov.rPinecone10-3.assignments_2020-11-11.csv"))

Alternatively, use a bootstrapped version of rPinecone clusters (run on command line due to the time taken to iterate over 100 trees) Testing external pinecone (took about 3 hrs to run rPinecone over 100 bootstrap trees for the full dataset)


pinecone.10 <- read.csv(pinecone.10.file, stringsAsFactors=F)

length(unique(pinecone.10$Sub.lineage))
[1] 37
length(unique(pinecone.10$pinecone_95))
[1] 190
length(unique(pinecone.10$pinecone_80))
[1] 66
length(unique(pinecone.10$pinecone_50))
[1] 46
length(unique(pinecone.10$pinecone_20))
[1] 38
length(unique(pinecone.10$pinecone_5))
[1] 25
plot__pinecone.bootstraps <- function(external.pinecone.clustering) {
  gg <- ggtree(TPA.MLtree)
  f2 <- facet_plot(gg, panel = "rPinecone ML tree", data = external.pinecone.clustering, geom = geom_tile, 
                   aes(x = as.numeric(factor(Sub.lineage))), fill = "blue")
  f2 <- facet_plot(f2, panel = "rPinecone 95%", data = external.pinecone.clustering, geom = geom_tile, 
                   aes(x = as.numeric(factor(pinecone_95))), fill = "red")
  f2 <- facet_plot(f2, panel = "rPinecone 80%", data = external.pinecone.clustering, geom = geom_tile, 
                   aes(x = as.numeric(factor(pinecone_80))), fill = "blue")
  f2 <- facet_plot(f2, panel = "rPinecone 50%", data = external.pinecone.clustering, geom = geom_tile, 
                   aes(x = as.numeric(factor(pinecone_50))), fill = "red")
  f2 <- facet_plot(f2, panel = "rPinecone 20%", data = external.pinecone.clustering, geom = geom_tile, 
                   aes(x = as.numeric(factor(pinecone_20))), fill = "blue")
  f2 <- facet_plot(f2, panel = "rPinecone 5%", data = external.pinecone.clustering, geom = geom_tile, 
                   aes(x = as.numeric(factor(pinecone_5))), fill = "red") +
    theme(strip.background =element_rect(fill="white"),strip.text = element_text(size= 8)) +
    theme.text.size
  return(f2)
}


p.pinecone.boootstrap.cluster.eval <- plot__pinecone.bootstraps(pinecone.10)

#Cairo::Cairo(file=paste0(Figure_output_directory, "Supplementary_Figure3_Global-TPA.good-MLtree_vs_rPinecone-thresholds_02-2021.svg"), width = 600, height = 600,type="svg",units = "pt")
p.pinecone.boootstrap.cluster.eval

#dev.off()

rPinecone clusters are dependent on both SNP distance and tree topology. Bootstrapping these clusters is very hard, because the data are so clonal - particularly at the top of the tree. Removing just a few columns for a bootstrap can change the topology of the very clonal cluster. However, it is clear that many of these clusters elsewhere are still valid and reproducible at even very stringent support criteria. Therefore, for consistency, decided to require the same clusters to be present in at least 5% of trees - this robust allows amalgamation of the top clade into a coherent group.

Since paper was largely analysed using non-bootstrapped clusters, will aim to use the same ordering scheme (but only use robust clusters).

pinecone.10.3__5pc <- unique(pinecone.10[,c("Sub.lineage","pinecone_5")])

# want to rename bootstrapped clusters to be reasonably consistent with consensus tree analysis, and ensure sensible order on tree)
pinecone.10.3__5pc <- data.frame(pinecone.10 %>% dplyr::group_by(pinecone_5) %>% summarise(count=n()))
`summarise()` ungrouping output (override with `.groups` argument)
pinecone.10.3__5pc$is.singleton <- ifelse(pinecone.10.3__5pc$count==1,"singleton", "multi")
pinecone.10.3__5pc <- plyr::join(pinecone.10.3__5pc, unique(pinecone.10[,c("Sub.lineage","pinecone_5")]), by="pinecone_5", type='full')
pinecone.10.3__5pc$Sub.lineage.sing <- sapply(1:nrow(pinecone.10.3__5pc), function(x) ifelse(grepl("singleton",pinecone.10.3__5pc$Sub.lineage[x]),23,pinecone.10.3__5pc$Sub.lineage[x]))
pinecone.10.3__5pc <- pinecone.10.3__5pc[order(as.numeric(pinecone.10.3__5pc$Sub.lineage.sing),pinecone.10.3__5pc$Sub.lineage),]

# Now extract non-singletons and rename in order
new.names <- pinecone.10.3__5pc[pinecone.10.3__5pc$Sub.lineage.sing!=23,]
new.names <- data.frame(pinecone_5=unique(new.names$pinecone_5), stringsAsFactors = F)
new.names$pinecone_5_newname <- c(1:nrow(new.names))
# Now extract singletons and rename 
new.names.sing <- pinecone.10.3__5pc[pinecone.10.3__5pc$is.singleton=="singleton",]
new.names.sing <- data.frame(pinecone_5=unique(new.names.sing$pinecone_5), stringsAsFactors = F)
new.names.sing$pinecone_5_newname <- "Singleton"
# Combine new name list
new.names <- rbind(new.names,new.names.sing)
# integrate into list of types
pinecone.10.3__5pc <- plyr::join(pinecone.10.3__5pc, new.names, by="pinecone_5", type='left')

# now apply back to samples 
pinecone.10 <- plyr::join(pinecone.10, (unique(pinecone.10.3__5pc[,c("pinecone_5","pinecone_5_newname")])), by="pinecone_5", type="left")
pinecone.10$pinecone_5_newname.numeric <- as.numeric(sapply(1:nrow(pinecone.10), function(x) ifelse(grepl("Singleton",pinecone.10$pinecone_5_newname[x]),18,pinecone.10$pinecone_5_newname[x])))

re-import rPinecone classifications (original analysis)


pinecone.clusters2 <- read.csv(pinecone.clusters.MLoriginal.file, row.names=1, comment.char="", check.names=F)



pinecone.clusters <- data.frame(pinecone.clusters2, stringsAsFactors = F)

#TPA.meta1.2
colnames(pinecone.clusters) <- c("Sample_Name", "pinecone.sublin.raw","pinecone.major.lin.raw", "TPA.pinecone.sublineage.pyjar")

# do some relabelling of major lineages
pinecone.clusters$TPA.pinecone.major <- ifelse(pinecone.clusters$pinecone.major.lin.raw=="0","outlier", ifelse(pinecone.clusters$pinecone.major.lin.raw=="1", "SS14", "Nichols"))

Integrate pinecone data with full meta

TPA.meta1.2.pinecone <- plyr::join(pinecone.clusters[,c("Sample_Name","TPA.pinecone.sublineage.pyjar","TPA.pinecone.major")], TPA.meta1.2, by="Sample_Name", type="left")

TPA.meta1.2.pinecone <- plyr::join(data.frame(Sample_Name=pinecone.10$Taxa, TPA.pinecone.sublineage=pinecone.10$pinecone_5_newname, stringsAsFactors = F),TPA.meta1.2.pinecone, by="Sample_Name", type="left")
# How many Nichols are there?
nrow(TPA.meta1.2.pinecone[TPA.meta1.2.pinecone$TPA_Lineage=="Nichols",])
[1] 102
# How many SS14 are there?
nrow(TPA.meta1.2.pinecone[TPA.meta1.2.pinecone$TPA_Lineage=="SS14",])
[1] 426
# How many outliers are there? (these are technically SS14/Nichols, but also basal in the phylogeny)
nrow(TPA.meta1.2.pinecone[TPA.meta1.2.pinecone$TPA.pinecone.major=="outlier",])
[1] 4
# what are the outlier (non-SS14/Nihols) genomes?
TPA.meta1.2.pinecone[TPA.meta1.2.pinecone$TPA.pinecone.major=="outlier",]

# How many Singletons are there?
nrow(TPA.meta1.2.pinecone[grepl("Singleton",TPA.meta1.2.pinecone$TPA.pinecone.sublineage),])
[1] 8
(TPA.meta1.2.pinecone[grepl("Singleton",TPA.meta1.2.pinecone$TPA.pinecone.sublineage),])

# How many Nichols Singletons are there?
nrow(TPA.meta1.2.pinecone[(grepl("Singleton",TPA.meta1.2.pinecone$TPA.pinecone.sublineage) & TPA.meta1.2.pinecone$TPA_Lineage=="Nichols"),])
[1] 4
# How many SS14 Singletons are there?
nrow(TPA.meta1.2.pinecone[(grepl("Singleton",TPA.meta1.2.pinecone$TPA.pinecone.sublineage) & TPA.meta1.2.pinecone$TPA_Lineage=="SS14"),])
[1] 4
(TPA.meta1.2.pinecone[(grepl("Singleton",TPA.meta1.2.pinecone$TPA.pinecone.sublineage) & TPA.meta1.2.pinecone$TPA_Lineage=="SS14"),])
NA

Of the countries that have both Nichols and SS14, what is the breakdown?

# Which countries have both SS14 and Nichols?
Countries.both.lineages <- data.frame(unique(TPA.meta1.2[,c("Geo_Country","TPA_Lineage")]) %>% dplyr::group_by(Geo_Country) %>% dplyr::summarise(count=n()))
`summarise()` ungrouping output (override with `.groups` argument)
Countries.both.lineages <- Countries.both.lineages[Countries.both.lineages$count==2,"Geo_Country"]

# Proportion of Nichols/SS14 in this subset of countries
TPA.meta1.2[TPA.meta1.2$Geo_Country %in% Countries.both.lineages,] %>% 
  dplyr::group_by(TPA_Lineage) %>%
  summarise(count=n()) %>%
  mutate(percentage=(count/sum(count))*100)
`summarise()` ungrouping output (override with `.groups` argument)
# and by country
Lineage.perc.country <- data.frame(TPA.meta1.2[TPA.meta1.2$Geo_Country %in% Countries.both.lineages,] %>% 
  dplyr::group_by(Geo_Country,TPA_Lineage) %>%
  summarise(count=n()) %>%
  mutate(percentage=(count/sum(count))*100),stringsAsFactors = F)
`summarise()` regrouping output by 'Geo_Country' (override with `.groups` argument)
Lineage.perc.country

median(Lineage.perc.country[Lineage.perc.country$TPA_Lineage=="SS14","percentage"])
[1] 75.2907

Description of the new dataset

# Total samples in good tree
nrow(TPA.meta1.2.pinecone)
[1] 528
# Total 'new' samples in good tree
unique(TPA.meta1.2.pinecone$Citation)
 [1] "This_Study"            "Beale_2019_Global_TPA" "Tong_2017"             "Sun_2016"              "Chen_2020"            
 [6] "Pětrošová_2013"        "Arora_2016"            "Pinto_2016"            "Grillová_2019"         "unpublished-Giacani"  
[11] "Čejková_2012"         
nrow(TPA.meta1.2.pinecone[TPA.meta1.2.pinecone$Citation %in% c("unpublished-WSI" ,"unpublished-Taiaroa"),])
[1] 0
nrow(TPA.meta1.2.pinecone[TPA.meta1.2.pinecone$Citation %notin% c("unpublished-WSI" ,"unpublished-Taiaroa"),])
[1] 528
nrow(TPA.meta1.2.pinecone[TPA.meta1.2.pinecone$Citation %in% c("This_Study"),])
[1] 401
nrow(TPA.meta1.2.pinecone[TPA.meta1.2.pinecone$Citation %notin% c("This_Study"),])
[1] 127

Define colours for sublineages

# Define sublineage clustering scheme using brew colourscales
#sublineages.cols.brew <- data.frame(unique(TPA.meta1.2.pinecone[,c("TPA.pinecone.major","TPA.pinecone.sublineage.pyjar")]), stringsAsFactors = F)
sublineages.cols.brew <- data.frame(unique(TPA.meta1.2.pinecone[,c("TPA.pinecone.major","TPA.pinecone.sublineage")]), stringsAsFactors = F)

sublineages.cols.brew <- sublineages.cols.brew[order(sublineages.cols.brew$TPA.pinecone.major,sublineages.cols.brew$TPA.pinecone.sublineage),]

sublineages.cols.brew$sublin.order <- as.numeric(as.character(sublineages.cols.brew$TPA.pinecone.sublineage))
NAs introduced by coercion
sublineages.cols.brew <- sublineages.cols.brew[order(sublineages.cols.brew$sublin.order),]



#sublineages.cols.brew$sublineage.cols <- c(brewer.pal(n=7,"Blues")[2:7],brewer.pal(n=6,"Purples")[2:6],"grey80",brewer.pal(n=4,"YlOrBr")[c(2,3)], brewer.pal(n=7,"Reds")[2:6],brewer.pal(n=5,"Greens")[2:5],"grey80") 

# For revised bootstrapped clusters
sublineages.cols.brew$sublineage.cols <- sublineages.cols.brew$sublineage.cols <- c("#FC9272","#EF3B2C",brewer.pal(n=4,"Greens")[2:4],brewer.pal(n=4,"YlOrBr")[c(2,3)],brewer.pal(n=6,"Blues")[2:6],brewer.pal(n=6,"Purples")[2:6],"grey80","grey80")
  


sublineages.cols.brew <- unique(sublineages.cols.brew[,c("TPA.pinecone.sublineage","sublineage.cols")])
sublineages.cols.brew <- sublineages.cols.brew[order(as.numeric(as.character(sublineages.cols.brew$TPA.pinecone.sublineage))),]
NAs introduced by coercion
sublineages.cols.brew$TPA.pinecone.sublineage <- factor(sublineages.cols.brew$TPA.pinecone.sublineage, levels=sublineages.cols.brew$TPA.pinecone.sublineage)

colnames(sublineages.cols.brew) <- c("sublineage","sublineage.cols")
sublineages.cols.brew <- unique(sublineages.cols.brew)

now plot trees

#TPA.MLtree.ggtree <- ggtree(TPA.MLtree,layout = "fan",open.angle = 20, right=T)
#TPA.pyjar.treeplot 

p.TPA.pyjar.treeplot.tipsublineages <- TPA.pyjar.treeplot %<+% data.frame(Sample_Name=TPA.meta1.2.pinecone$Sample_Name, Sublineage=TPA.meta1.2.pinecone$TPA.pinecone.sublineage,stringsAsFactors = F) + 
  geom_tippoint(aes(color=Sublineage), size=1, alpha=0.5) + 
  scale_color_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) 

p.TPA.pyjar.treeplot.stripsublineages <- gheatmap(TPA.pyjar.treeplot,
               data.frame(row.names=TPA.meta1.2.pinecone$Sample_Name, Sublineage=TPA.meta1.2.pinecone$TPA.pinecone.sublineage,stringsAsFactors = F), color=NULL,width=0.1,offset=0.0000005, colnames_angle=-45,colnames_offset_y=0.25, font.size=3) + 
  scale_fill_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) 
Scale for 'fill' is already present. Adding another scale for 'fill', which will replace the existing scale.
p.TPA.pyjar.treeplot.stripsublineages

Now for ML gubbins tree

TPA.MLtree.ggtree <- ggtree(TPA.MLtree,layout = "fan",open.angle = 20, right=T)
Scale for 'y' is already present. Adding another scale for 'y', which will replace the existing scale.
TPA.MLtree.ggtree.tippoint <- TPA.MLtree.ggtree %<+% data.frame(Sample_Name=TPA.meta1.2.pinecone$Sample_Name, Sublineage=TPA.meta1.2.pinecone$TPA.pinecone.sublineage,stringsAsFactors = F) + 
  geom_tippoint(aes(color=Sublineage), size=0.75, alpha=0.5) + 
  scale_color_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage)

p.TPA.MLtree.sublineages <- gheatmap(TPA.MLtree.ggtree.tippoint,
               data.frame(row.names=TPA.meta1.2.pinecone$Sample_Name, Sublineage=TPA.meta1.2.pinecone$TPA.pinecone.sublineage,stringsAsFactors = F), color=NULL,width=0.075,offset=0.00000025, colnames_angle=-45,colnames_offset_y=0.02, hjust=-0.0,font.size=2.25) + 
  scale_fill_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) +
  theme.text.size + theme(legend.key.size = unit(0.65,"line"),legend.position='right')
Scale for 'fill' is already present. Adding another scale for 'fill', which will replace the existing scale.
#p.TPA.MLtree.sublineages


#Cairo::Cairo(file=paste0(Figure_output_directory, "Supplementary_Figure2__goodcov-MLtree_circular__02-2021.svg"), width = 800, height = 800,type="svg",units = "pt")
p.TPA.MLtree.sublineages

#dev.off()

or a linear tree (which can also capture legend from)

TPA.ML.ggtree.linear <- ggtree(TPA.MLtree) %<+% data.frame(Sample_Name=TPA.meta1.2.pinecone$Sample_Name, Sublineage=TPA.meta1.2.pinecone$TPA.pinecone.sublineage,stringsAsFactors = F) + 
  geom_tippoint(aes(color=Sublineage), size=0.75, alpha=0.5, show.legend = F) + 
  scale_color_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) +
  # add bootstrap support
  geom_point2(aes(subset=(!isTip & as.numeric(label)>95)),size=1.5, shape=18) +
  #geom_point2(aes(subset=(!isTip & as.numeric(label)>95)),size=2.5, shape=18, alpha=0.5) +
  #geom_point2(aes(subset=(!isTip & as.numeric(label)>95)),size=1.5, shape=18, color='cyan', alpha=0.5) +
  NULL

p.TPA.ML.ggtree.linear <- gheatmap(TPA.ML.ggtree.linear,
               data.frame(row.names=TPA.meta1.2.pinecone$Sample_Name, Sublineage=TPA.meta1.2.pinecone$TPA.pinecone.sublineage,stringsAsFactors = F), color=NULL,width=0.075,offset=0.00000025, colnames_angle=0,colnames_offset_y=-1, font.size=2) + 
  scale_fill_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) +
  theme.text.size + theme(legend.key.size = unit(0.75,"line"),legend.position='bottom')
Scale for 'fill' is already present. Adding another scale for 'fill', which will replace the existing scale.
p.TPA.ML.ggtree.linear <- p.TPA.ML.ggtree.linear + new_scale_fill()

p.TPA.ML.ggtree.linear <- gheatmap(p.TPA.ML.ggtree.linear,TPA.rawseq.countries.p, color=NULL,width=0.075,offset=0.00000725, colnames_angle=0,colnames_offset_y=-1, font.size=2) + 
  scale_fill_manual(name="Country",values=continental.country.cols.brew2$country.col, breaks=continental.country.cols.brew2$Geo_Country) +
  theme.text.size + theme(legend.key.size = unit(0.65,"line"),legend.position='bottom') + 
  geom_treescale(fontsize = 2.5, x=0.000001, y=50) +
  NULL
Scale for 'fill' is already present. Adding another scale for 'fill', which will replace the existing scale.
p.TPA.ML.ggtree.linear


# Capture legend from full tree
p.TPA.ML.ggtree.linear.legend <- get_legend(p.TPA.ML.ggtree.linear)
NAs introduced by coercionNAs introduced by coercion

Define subtrees using ‘collapse’ clade


#ggtree(TPA.MLtree,layout = "fan",open.angle = 20, right=T) + geom_text2(aes(subset=!isTip, label=node), hjust=-.3) 
#ggtree(TPA.MLtree) + geom_text2(aes(subset=!isTip, label=node), hjust=-.3, size=3) 

SS14.subtree.nodeid <- 530 # 529
Nichols.subtree.nodeid <- 955 

Nichols subtree (with collapsed SS14)


#TPA.ML.ggtree.linear + geom_text2(aes(subset=!isTip, label=node), hjust=-.3, size=3) 

Nichols.coll <- ggtree(TPA.MLtree) %>% collapse(node=SS14.subtree.nodeid)

# Collaping node reduces 'y' position, so lets add some back for proper spacing
Nichols.coll$data[Nichols.coll$data$node==SS14.subtree.nodeid,"y"] <- Nichols.coll$data[Nichols.coll$data$node==SS14.subtree.nodeid,"y"] + 10

# now add triangle and text
Nichols.coll <- Nichols.coll + geom_text2(aes(subset=(node == SS14.subtree.nodeid)), size=20, label=intToUtf8(9664), hjust=0.2,vjust=.55, family="OpenSansEmoji", color="indianred1", alpha=.75)
Nichols.coll <- Nichols.coll + geom_text2(aes(subset=(node == SS14.subtree.nodeid)), cex=3, vjust=0.2, label="SS14",hjust = -1.5)
Nichols.coll <- Nichols.coll %<+% data.frame(Sample_Name=TPA.meta1.2.pinecone$Sample_Name, Sublineage=TPA.meta1.2.pinecone$TPA.pinecone.sublineage,stringsAsFactors = F) + 
  geom_tippoint(aes(color=Sublineage), size=1, alpha=0.25,show.legend=F) + 
  scale_color_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) +
  # add bootstrap support
  geom_point2(aes(subset=(!isTip & as.numeric(label)>95)),size=1.5, shape=18) +
  #geom_point2(aes(subset=(!isTip & as.numeric(label)>95)),size=2.5, shape=18, alpha=0.5) +
  #geom_point2(aes(subset=(!isTip & as.numeric(label)>95)),size=1.5, shape=18, color="cyan", alpha=0.5) +
  NULL


p.TPA.Nichols.coll <- gheatmap(Nichols.coll,
               data.frame(row.names=TPA.meta1.2.pinecone$Sample_Name, Sublineage=TPA.meta1.2.pinecone$TPA.pinecone.sublineage,stringsAsFactors = F), color=NULL,width=0.085,offset=0.00000025, colnames_angle=0,colnames_offset_y=-1, font.size=2) + 
  scale_fill_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) +
  theme.text.size + theme(legend.key.size = unit(0.85,"line"),legend.position='none')

p.TPA.Nichols.coll <- p.TPA.Nichols.coll + new_scale_fill()

p.TPA.Nichols.coll <- gheatmap(p.TPA.Nichols.coll,TPA.rawseq.countries.p, color=NULL,width=0.085,offset=0.00001025, colnames_angle=0,colnames_offset_y=-1, font.size=2) + 
  scale_fill_manual(name="Country",values=continental.country.cols.brew2$country.col, breaks=continental.country.cols.brew2$Geo_Country) +
  theme.text.size + theme(legend.key.size = unit(0.75,"line"),legend.position='none') +
  geom_treescale(fontsize = 2.5, x=0.000002, y=25) + 
  ylim(-3,116) +
  #ggtitle("Nichols-lineage phylogeny") +
  NULL
p.TPA.Nichols.coll

SS14 subtree (with collapsed Nichols)


#TPA.ML.ggtree.linear + geom_text2(aes(subset=!isTip, label=node), hjust=-.3, size=3) 

SS14.coll <- ggtree(TPA.MLtree) %>% collapse(node=Nichols.subtree.nodeid)

# Collaping node reduces 'y' position, so lets add some back for proper spacing
SS14.coll$data[SS14.coll$data$node==Nichols.subtree.nodeid,"y"] <- SS14.coll$data[SS14.coll$data$node==Nichols.subtree.nodeid,"y"] - 25

SS14.coll <- SS14.coll + geom_text2(aes(subset=(node == Nichols.subtree.nodeid)), size=20, label=intToUtf8(9664), hjust=0.2,vjust=.55, family="OpenSansEmoji", color="royalblue2", alpha=.85)
SS14.coll <- SS14.coll + geom_text2(aes(subset=(node == Nichols.subtree.nodeid)), cex=3, vjust=0.2, label="Nichols",hjust = -1)
SS14.coll <- SS14.coll %<+% data.frame(Sample_Name=TPA.meta1.2.pinecone$Sample_Name, Sublineage=TPA.meta1.2.pinecone$TPA.pinecone.sublineage,stringsAsFactors = F) + 
  geom_tippoint(aes(color=Sublineage), size=1, alpha=0.25,show.legend=F) + 
  scale_color_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) +
  # add bootstrap support
  geom_point2(aes(subset=(!isTip & as.numeric(label)>95)),size=1.5, shape=18) +
  #geom_point2(aes(subset=(!isTip & as.numeric(label)>95)),size=2.0, shape=18, alpha=0.25) +
  #geom_point2(aes(subset=(!isTip & as.numeric(label)>95)),size=1.5, shape=18, color="cyan", alpha=0.5) +
  NULL
#SS14.coll


p.TPA.SS14.coll <- gheatmap(SS14.coll,
               data.frame(row.names=TPA.meta1.2.pinecone$Sample_Name, Sublineage=TPA.meta1.2.pinecone$TPA.pinecone.sublineage,stringsAsFactors = F), color=NULL,width=0.085,offset=0.00000025, colnames_angle=0,colnames_offset_y=-1, font.size=2) + 
  scale_fill_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) +
  theme.text.size + theme(legend.key.size = unit(0.65,"line"),legend.position='none')

p.TPA.SS14.coll <- p.TPA.SS14.coll + new_scale_fill()

p.TPA.SS14.coll <- gheatmap(p.TPA.SS14.coll,TPA.rawseq.countries.p, color=NULL,width=0.085,offset=0.00001025, colnames_angle=0,colnames_offset_y=-1, font.size=2) + 
  scale_fill_manual(name="Country",values=continental.country.cols.brew2$country.col, breaks=continental.country.cols.brew2$Geo_Country) +
  theme.text.size + theme(legend.key.size = unit(0.65,"line"),legend.position='none') +
  geom_treescale(fontsize = 2.5, x=0.000002, y=65) +
  #ggtitle("SS14-lineage phylogeny") +
  ylim(-30,429) +
  NULL

p.TPA.SS14.coll

Plot collapsed trees together


# make Nichols tree shorter
coll.trees.nichols.shorter <- plot_grid(NULL, p.TPA.Nichols.coll, NULL, ncol=1, rel_heights=c(2,7,1))

#coll.trees.row.1 <- plot_grid(p.TPA.Nichols.coll,p.TPA.SS14.coll,ncol=2, rel_widths=c(1,1), labels=c('Nichols','SS14'),label_size = 11)
#coll.trees.row.1 <- plot_grid(p.TPA.Nichols.coll,p.TPA.SS14.coll,ncol=2, rel_widths=c(1,1), labels=c('A','B'),label_size = 11)

#coll.trees.row.1 <- plot_grid(coll.trees.nichols.shorter,p.TPA.SS14.coll,ncol=2, rel_widths=c(1,1), labels=c('A','B'),label_size = 11)
coll.trees.row.1 <- plot_grid(p.TPA.SS14.coll,coll.trees.nichols.shorter,ncol=2, rel_widths=c(1,1), labels=c('A - SS14-lineage phylogeny','B - Nichols-lineage phylogeny'),label_size = 11)


coll.trees.row.2 <- plot_grid(p.TPA.ML.ggtree.linear.legend,ncol=1,labels='Key',label_size = 11)
coll.trees.combined <- plot_grid(coll.trees.row.1, coll.trees.row.2, ncol=1, rel_heights=c(3,1), scale=0.95)

coll.trees.combined

Sublineage timeline bubbleplot


#TPA.sublineages.counts <- TPA.meta1.2.pinecone[(TPA.meta1.2.pinecone$Sample_Year!="-" & TPA.meta1.2.pinecone$TPA.pinecone.sublineage!="Singleton"),] %>% dplyr::group_by(Sample_Year, TPA.pinecone.sublineage) %>% 
#  dplyr::summarise(Count=n())

TPA.sublineages.counts <- TPA.meta1.2.pinecone[(TPA.meta1.2.pinecone$Sample_Year!="-" ),] %>% dplyr::group_by(Sample_Year, TPA.pinecone.sublineage) %>% 
  dplyr::summarise(Count=n())



TPA.sublineages.counts$Sample_Year <- ifelse(TPA.sublineages.counts$Sample_Year=="1960-1980","1970",TPA.sublineages.counts$Sample_Year)

TPA.sublineages.counts <- plyr::join(data.frame(Sample_Year=c(1912:2019),stringsAsFactors=F), TPA.sublineages.counts)
TPA.sublineages.counts <- TPA.sublineages.counts[!is.na(TPA.sublineages.counts$TPA.pinecone.sublineage),]
TPA.sublineages.counts$TPA.pinecone.sublineage <- factor(TPA.sublineages.counts$TPA.pinecone.sublineage, levels=rev(sublineages.cols.brew$sublineage))


p.sublineage.temporal.bubbleplot <- ggplot(TPA.sublineages.counts, aes(Sample_Year, TPA.pinecone.sublineage, colour=TPA.pinecone.sublineage)) +
  geom_point(alpha=0.65, aes(size=Count)) + 
  guides(colour=FALSE) +
  theme_light() +
  scale_size_area(max_size = 8,breaks=c(1,5,10,25,50,75,100)) +
  scale_color_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) +
  theme.text.size + theme(legend.key.size = unit(0.65,"line"),legend.position='right') +
  coord_cartesian(xlim=c(1950,2020)) +
  labs(y="Sublineage", x="Sample Year")

p.sublineage.temporal.bubbleplot.legend <- get_legend(p.sublineage.temporal.bubbleplot)

p.sublineage.temporal.bubbleplot

#sublineage.counts <- TPA.meta1.2.pinecone[(TPA.meta1.2.pinecone$Sample_Year!="-" & TPA.meta1.2.pinecone$TPA.pinecone.sublineage!="Singleton"),] %>% group_by(TPA.pinecone.sublineage) %>% summarise(Count=n())
sublineage.counts <- TPA.meta1.2.pinecone[(TPA.meta1.2.pinecone$Sample_Year!="-" ),] %>% group_by(TPA.pinecone.sublineage) %>% summarise(Count=n())
`summarise()` ungrouping output (override with `.groups` argument)
sublineage.counts$TPA.pinecone.sublineage <- factor(sublineage.counts$TPA.pinecone.sublineage,levels=rev(sublineages.cols.brew$sublineage))

p.sublineage.hbarplot <- ggplot(sublineage.counts, aes(Count,TPA.pinecone.sublineage,fill=TPA.pinecone.sublineage)) +
  geom_barh(stat="identity", position="stack", width=0.75) +
  theme_light() +
  theme.text.size + theme(legend.key.size = unit(0.65,"line"),legend.position='none') +
  #scale_fill_manual(name="Country",values=sublineage.counts$TPA.pinecone.sublineage, breaks=sublineage.counts$Geo_Country) +
  scale_fill_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) +
  geom_text(data=sublineage.counts, aes((Count+10), TPA.pinecone.sublineage,label=Count), size=2.5, inherit.aes = F) +
  labs(y="Sublineage", x="Samples/Sublineage")
p.sublineage.hbarplot  

Proportion by country

#sublineage.country.counts <- TPA.meta1.2.pinecone[(TPA.meta1.2.pinecone$Sample_Year!="-" & TPA.meta1.2.pinecone$TPA.pinecone.sublineage!="Singleton"),] %>% group_by(TPA.pinecone.sublineage, Geo_Country) %>% summarise(Count=n())
sublineage.country.counts <- TPA.meta1.2.pinecone[(TPA.meta1.2.pinecone$Sample_Year!="-" ),] %>% group_by(TPA.pinecone.sublineage, Geo_Country) %>% summarise(Count=n())
`summarise()` regrouping output by 'TPA.pinecone.sublineage' (override with `.groups` argument)
sublineage.country.counts$TPA.pinecone.sublineage <- factor(sublineage.country.counts$TPA.pinecone.sublineage,levels=rev(sublineages.cols.brew$sublineage))

p.sublineage.country.hbarplot <- ggplot(sublineage.country.counts, aes(Count,TPA.pinecone.sublineage,fill=Geo_Country)) +
  geom_barh(stat="identity", position="fill", width=0.75) +
  theme_light() +
  theme.text.size + theme(legend.key.size = unit(0.65,"line"),legend.position='none') +
  scale_fill_manual(name="Country",values=continental.country.cols.brew2$country.col, breaks=continental.country.cols.brew2$Geo_Country) +
  labs(y="Sublineage", x="Country Proportion")
p.sublineage.country.hbarplot

p.sublineage.timeline.bubbleplot.combined <- plot_grid(p.sublineage.temporal.bubbleplot + theme(legend.position="none"), p.sublineage.hbarplot + y.theme.strip, p.sublineage.country.hbarplot + y.theme.strip, p.sublineage.temporal.bubbleplot.legend, ncol=4, align=T, rel_widths=c(5,2,2,1),labels=c('C','D','E',''),label_size = 11,vjust=-0.25) #+ theme(legend.position="right")


gg.colltrees.sublineage.distributions <- plot_grid(coll.trees.combined, p.sublineage.timeline.bubbleplot.combined, ncol=1, rel_heights=c(5,2))
#gg.colltrees.sublineage.distributions

#Cairo::Cairo(file=paste0(Figure_output_directory, "Figure2__goodcov-MLtree_+sublineage-distros__02-2021.svg"), width = 900, height = 900,type="svg",units = "pt")
gg.colltrees.sublineage.distributions

#dev.off()

Now take a deep dive into Single country/region sublineage dynamics (UK-wide v.s. British Columbia, Canada)


TPA.sublineage_UK.Canada.temporal <- TPA.meta1.2.pinecone[(TPA.meta1.2.pinecone$Geo_Country=="UK" | TPA.meta1.2.pinecone$Geo_Region=="British_Columbia"),]

TPA.sublineage_UK.Canada.temporal.counts <- data.frame(TPA.sublineage_UK.Canada.temporal %>% dplyr::group_by(TPA.pinecone.sublineage,Sample_Year,Geo_Country,TPA.pinecone.major) %>% 
  dplyr::summarise(Sample.Count=n()), stringsAsFactors = F)
`summarise()` regrouping output by 'TPA.pinecone.sublineage', 'Sample_Year', 'Geo_Country' (override with `.groups` argument)
# Fix dates and make continuous
TPA.sublineage_UK.Canada.temporal.counts$Sample_Year <- as.numeric(TPA.sublineage_UK.Canada.temporal.counts$Sample_Year)


TPA.sublineage_UK.Canada.temporal.counts <- plyr::join(data.frame(Sample_Year=c(1912:2019),stringsAsFactors=F),TPA.sublineage_UK.Canada.temporal.counts, by="Sample_Year", type="left")

TPA.sublineage_UK.Canada.temporal.counts <- TPA.sublineage_UK.Canada.temporal.counts[!is.na(TPA.sublineage_UK.Canada.temporal.counts$TPA.pinecone.sublineage),]

# order by sublineage
TPA.sublineage_UK.Canada.temporal.counts$TPA.pinecone.sublineage <- factor(TPA.sublineage_UK.Canada.temporal.counts$TPA.pinecone.sublineage, levels=rev(sublineages.cols.brew$sublineage))

# make bubbleplot
plot.TPA.sublineage_UK.Canada.temporal.counts.bubbleplot <- 
  ggplot(TPA.sublineage_UK.Canada.temporal.counts, aes(Sample_Year, TPA.pinecone.sublineage, color=TPA.pinecone.sublineage)) +
  geom_point(alpha=0.70,aes(size=Sample.Count)) + 
  geom_line(alpha=0.25) +
  theme_light() +
  labs(x="Sample Year", y="Sublineage", size="Sample Count") +
  coord_cartesian(xlim=c(2000,2020)) +
  theme(strip.text.y = element_text(angle = 0)) + 
  scale_color_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) +
  facet_grid(.~Geo_Country) + 
  scale_size_area(max_size = 10,breaks=c(1,5,10,20,30,40,50)) +
  theme.text.size + 
  theme(legend.key.size = unit(0.65,"line")) +
  theme(strip.background = element_rect(color='white', fill='white',linetype="solid"), strip.text.x = element_text(color = "grey25")) +
  NULL
plot.TPA.sublineage_UK.Canada.temporal.counts.bubbleplot 

NA
NA

get population prevalence stats


UK.stats <- read.table(UK.stats.file,sep="\t",header=T)
UK.stats$Country <- "UK"


BC.stats <- read.table(BC.stats.file,sep="\t",header=T)
BC.stats$Country <- "British Columbia"

UK.BC.stats.combined <- rbind(UK.stats,BC.stats)
UK.BC.stats.combined[UK.BC.stats.combined$Country=="UK","Country"] <- "England"


plot.UK.BC.stats.combined <- ggplot(UK.BC.stats.combined, aes(Year,Total)) + 
  geom_line() +
  theme_light() +
  labs(x="Year",y="Syphilis Incidence/100,000") + 
  #scale_x_continuous(breaks=seq(2008,2019,2)) +
  coord_cartesian(xlim=c(2000,2020)) +
  #ggtitle("Syphilis Incidence data") +
  facet_grid(.~Country) +
  theme.text.size +
  theme(strip.background = element_rect(fill='white',linetype="solid"), strip.text.x = element_text(color = "grey25", size=10))
plot.UK.BC.stats.combined

plot_grid(plot.UK.BC.stats.combined + x.theme.strip + ggtitle("Syphilis Incidence and sublineage count"), plot.TPA.sublineage_UK.Canada.temporal.counts.bubbleplot + theme(legend.position="bottom",strip.background = element_blank(),strip.text.x = element_blank()), ncol=1, align=T, rel_heights=c(1,2), labels=c('A','B'), label_size=11)

some stats about the canadian outbreak

BC.sublineage.summary <- data.frame(TPA.meta1.2.pinecone[TPA.meta1.2.pinecone$Geo_Region=="British_Columbia",] %>% dplyr::group_by(TPA.pinecone.sublineage,Geo_Country,TPA.pinecone.major) %>% dplyr::summarise(Sample.Count=n()), stringsAsFactors = F)
`summarise()` regrouping output by 'TPA.pinecone.sublineage', 'Geo_Country' (override with `.groups` argument)
(BC.sublineage.summary[BC.sublineage.summary$TPA.pinecone.sublineage==1,"Sample.Count"]/sum(BC.sublineage.summary$Sample.Count))*100
[1] 82.14286
BC.sublineage.summary.pre2010 <- data.frame(TPA.meta1.2.pinecone[(TPA.meta1.2.pinecone$Geo_Region=="British_Columbia" & TPA.meta1.2.pinecone$Sample_Year<=2010),] %>% dplyr::group_by(TPA.pinecone.sublineage,Geo_Country,TPA.pinecone.major) %>% dplyr::summarise(Sample.Count=n()), stringsAsFactors = F)
`summarise()` regrouping output by 'TPA.pinecone.sublineage', 'Geo_Country' (override with `.groups` argument)
(BC.sublineage.summary.pre2010[BC.sublineage.summary.pre2010$TPA.pinecone.sublineage==1,"Sample.Count"]/sum(BC.sublineage.summary.pre2010$Sample.Count))*100
[1] 85.71429
BC.sublineage.summary.post2011 <- data.frame(TPA.meta1.2.pinecone[(TPA.meta1.2.pinecone$Geo_Region=="British_Columbia" & TPA.meta1.2.pinecone$Sample_Year>=2011),] %>% dplyr::group_by(TPA.pinecone.sublineage,Geo_Country,TPA.pinecone.major) %>% dplyr::summarise(Sample.Count=n()), stringsAsFactors = F)
`summarise()` regrouping output by 'TPA.pinecone.sublineage', 'Geo_Country' (override with `.groups` argument)
(BC.sublineage.summary.post2011[BC.sublineage.summary.post2011$TPA.pinecone.sublineage==1,"Sample.Count"]/sum(BC.sublineage.summary.post2011$Sample.Count))*100
[1] 81.42857

and the UK dataset

UK.sublineage.summary <- data.frame(TPA.meta1.2.pinecone[TPA.meta1.2.pinecone$Geo_Country=="UK",] %>% dplyr::group_by(TPA.pinecone.sublineage,Geo_Country,TPA.pinecone.major) %>% dplyr::summarise(Sample.Count=n()), stringsAsFactors = F)
`summarise()` regrouping output by 'TPA.pinecone.sublineage', 'Geo_Country' (override with `.groups` argument)


# Now look more globally
Sublineages per country - note that this plot does not account for multiple Singletons being in the same country - replaced.

sublineage.count.per.country <- data.frame(unique(TPA.meta1.2.pinecone[,c("TPA.pinecone.sublineage","Geo_Country")]) %>% dplyr::group_by(Geo_Country) %>%
  dplyr::summarise(count=n()), stringsAsFactors = F)
`summarise()` ungrouping output (override with `.groups` argument)
sublineage.count.per.country$Geo_Country <- factor(sublineage.count.per.country$Geo_Country, levels=continental.country.cols.brew2$Geo_Country)


p.sublineages.per.country.bar <- ggplot(sublineage.count.per.country, aes(Geo_Country, count, fill=Geo_Country)) + 
  geom_bar(stat='identity', width=0.75) + 
  scale_fill_manual(name="Country",values=continental.country.cols.brew2$country.col, breaks=continental.country.cols.brew2$Geo_Country) + 
  theme_light() +
  x.theme.axis.rotate + 
  theme.text.size +
  labs(x="Country", y="Sublineages/Country") +
  theme(legend.key.size = unit(0.65,"line"),legend.position='bottom') + 
  scale_y_continuous(breaks=seq(0,14,2))

p.sublineages.per.country.bar

Look at Singleton, private, and multi-country sublineages

# How many Singleton lineages are in each country?
Singleton.country.counts <- data.frame(TPA.meta1.2.pinecone[TPA.meta1.2.pinecone$TPA.pinecone.sublineage=="Singleton",c("Sample_Name","Geo_Country")] %>% 
  dplyr::group_by(Geo_Country) %>%
  dplyr::summarise(per.country=n()), stringsAsFactors = F)
`summarise()` ungrouping output (override with `.groups` argument)
Singleton.country.counts <- plyr::join(data.frame(Geo_Country=c(unique(TPA.meta1.2.pinecone$Geo_Country))), Singleton.country.counts, by="Geo_Country", type="left")
Singleton.country.counts[is.na(Singleton.country.counts$per.country),"per.country"] <- 0
Singleton.country.counts$lineage.type <- "Singleton in country"

Singleton.country.counts
TPA.meta1.2.pinecone[TPA.meta1.2.pinecone$TPA.pinecone.sublineage=="Singleton","TPA_Lineage"]
[1] "SS14"    "SS14"    "SS14"    "SS14"    "Nichols" "Nichols" "Nichols" "Nichols"
Private.country.counts <- unique(TPA.meta1.2.pinecone[TPA.meta1.2.pinecone$TPA.pinecone.sublineage!="Singleton",c("TPA.pinecone.sublineage", "Geo_Country")]) %>% 
  dplyr::group_by(TPA.pinecone.sublineage) %>%
  summarise(Countries.count=n(),.groups="keep")
Private.country.counts$private.distro <- ifelse(Private.country.counts$Countries.count==1,"private","multicountry")

Private.country.counts

# How many private lineages are in each country?
Private.country.locations <- unique(TPA.meta1.2.pinecone[TPA.meta1.2.pinecone$TPA.pinecone.sublineage %in% as.character(unlist(Private.country.counts[Private.country.counts$private.distro=='private',"TPA.pinecone.sublineage"])),c(c("TPA.pinecone.sublineage", "Geo_Country"))])
Private.country.location.counts <- Private.country.locations %>% dplyr::group_by(Geo_Country) %>%
  dplyr::summarise(per.country=n())
`summarise()` ungrouping output (override with `.groups` argument)
Private.country.location.counts <- plyr::join(data.frame(Geo_Country=c(unique(TPA.meta1.2.pinecone$Geo_Country)),stringsAsFactors = F), Private.country.location.counts, by="Geo_Country", type="left")
Private.country.location.counts[is.na(Private.country.location.counts$per.country),"per.country"] <- 0
Private.country.location.counts$lineage.type <- "Private sublineage to country"

# How many multicountry lineages are in each country?
multi.country.locations.counts <- unique(TPA.meta1.2.pinecone[TPA.meta1.2.pinecone$TPA.pinecone.sublineage %in% as.character(unlist(Private.country.counts[Private.country.counts$private.distro=='multicountry',"TPA.pinecone.sublineage"])),c(c("TPA.pinecone.sublineage", "Geo_Country"))])
multi.country.locations.counts <- multi.country.locations.counts %>% dplyr::group_by(Geo_Country) %>%
  dplyr::summarise(per.country=n())
`summarise()` ungrouping output (override with `.groups` argument)
multi.country.locations.counts <- plyr::join(data.frame(Geo_Country=c(unique(TPA.meta1.2.pinecone$Geo_Country)),stringsAsFactors = F), multi.country.locations.counts, by="Geo_Country", type="left")
multi.country.locations.counts[is.na(multi.country.locations.counts$per.country),"per.country"] <- 0
multi.country.locations.counts$lineage.type <- "Multi-country sublineage"

classified.sublineages.per.country <- rbind(multi.country.locations.counts,Private.country.location.counts,Singleton.country.counts)
classified.sublineages.per.country$Geo_Country <- factor(classified.sublineages.per.country$Geo_Country, levels=continental.country.cols.brew2$Geo_Country)
classified.sublineages.per.country$lineage.type <- factor(classified.sublineages.per.country$lineage.type, levels=rev(unique(classified.sublineages.per.country$lineage.type)))

plot.classified.sublineages.per.country <- ggplot(classified.sublineages.per.country, aes(Geo_Country, per.country, fill=lineage.type)) +
  geom_bar(position="stack", stat="identity", width=0.75) +
  theme_light() + 
  theme.text.size + 
  x.theme.axis.rotate +
  labs(x="Country",y="Sublineage/Country", fill="Sublineage Type") +
  scale_y_continuous(breaks=seq(0,18,2)) +
  theme(legend.key.size = unit(0.65,"line"),legend.position='right') + 
  ggtitle("Sublineage types by country") + 
  theme(plot.title = element_text(size = 10)) +
  scale_fill_manual(values=c("grey80","grey50","grey10"))
plot.classified.sublineages.per.country


plot.classified.sublineages.per.country.hbar <- ggplot(classified.sublineages.per.country, aes(per.country,Geo_Country, fill=lineage.type)) +
  geom_barh(position="stack", stat="identity", width=0.75) +
  theme_light() + 
  theme.text.size + 
  #x.theme.axis.rotate +
  labs(y="Country",x="Sublineage Count", fill="Sublineage Type") +
  scale_x_continuous(breaks=seq(0,18,2)) +
  theme(legend.key.size = unit(0.65,"line"),legend.position='right') + 
  #ggtitle("Sublineage types by country") + 
  theme(plot.title = element_text(size = 10)) +
  scale_fill_manual(values=c("grey80","grey50","grey10"))
plot.classified.sublineages.per.country.hbar



#plot_grid(p.sublineages.per.country.bar + theme(legend.position="none") + ggtitle("Number of sublineages in each country") + theme(plot.title = element_text(size=10)) + x.theme.strip, plot.classified.sublineages.per.country +theme(legend.position="bottom"), align=T, ncol=1, rel_heights=c(1,3))

Look at number of countries for each sublineage (v.s. sampling counts)

sublineage.country.distro.vs.total.counts <- plyr::join(data.frame(Private.country.counts,stringsAsFactors = F), sublineage.counts, by="TPA.pinecone.sublineage", type="left")

#library(ggrepel)
ggplot(sublineage.country.distro.vs.total.counts, aes(Count, Countries.count, size=Count, colour=TPA.pinecone.sublineage)) +
  geom_jitter(alpha=0.75) + 
  #geom_label_repel(data=sublineage.country.distro.vs.total.counts, aes(Count, Countries.count, label=TPA.pinecone.sublineage), segment.color = 'grey50', inherit.aes = F, size=2.5, box.padding=0.75) +
  #geom_point(alpha=0.75) + 
  scale_color_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) + 
  theme_light() + 
  scale_size_binned(range = c(1, 10),breaks=c(5,20,50,100,200,400)) +
  scale_x_log10() +
  scale_y_continuous(breaks=seq(0,20,2)) +
  labs(y="Countries (Count)", x="Samples (Count)", size="Sample Count") +
  theme(legend.key.size = unit(0.65,"line"),legend.position='bottom') 

Summary of sublineage classifications


sublineage.classification <- Private.country.counts
sublineage.classification <- sublineage.classification[order(as.numeric(sublineage.classification$TPA.pinecone.sublineage)),]

# How many private sublineages?
nrow(sublineage.classification[sublineage.classification$private.distro=='private',])
[1] 8
# How many mult-country sublineages?
nrow(sublineage.classification[sublineage.classification$private.distro=='multicountry',])
[1] 9
# Where are the Singletons
Singleton.country.counts[Singleton.country.counts$per.country!=0,]

# Where are the private lineages?
Private.country.location.counts[Private.country.location.counts$per.country!=0,]
NA

Pairwise SNP analyses

# import multiple sequence alignment
TPA.WGS.alignment.data <- pairsnp::import_fasta_sparse(TPA.MSA.SNPs.aln.file)

# run pairsnp
TPA.WGS.alignment.data.dist <- pairsnp::snp_dist(TPA.WGS.alignment.data)
TPA.WGS.alignment.data.dist.melt <- reshape2::melt(TPA.WGS.alignment.data.dist)
colnames(TPA.WGS.alignment.data.dist.melt) <- c("Taxa1", "Taxa2", "Distance")

# Bring in and merge metadata
TPA.meta1.2.pairwise.t1 <- TPA.meta1.2.pinecone[,c("Cleaned_fastq_id","Sample_Name","Sample_Year","Geo_Country","Continent","TPA.pinecone.major","TPA.pinecone.sublineage", "TPA_Lineage")]
colnames(TPA.meta1.2.pairwise.t1) <- paste0(colnames(TPA.meta1.2.pairwise.t1),".t1")
colnames(TPA.meta1.2.pairwise.t1)[2] <- "Taxa1"
TPA.meta1.2.pairwise.t2 <- TPA.meta1.2.pinecone[,c("Cleaned_fastq_id","Sample_Name","Sample_Year","Geo_Country","Continent","TPA.pinecone.major","TPA.pinecone.sublineage", "TPA_Lineage")]
colnames(TPA.meta1.2.pairwise.t2) <- paste0(colnames(TPA.meta1.2.pairwise.t2),".t2")
colnames(TPA.meta1.2.pairwise.t2)[2] <- "Taxa2"

TPA.alignment.data.dist.melt.meta <- plyr::join(TPA.WGS.alignment.data.dist.melt,TPA.meta1.2.pairwise.t1, by="Taxa1", type="left") 
TPA.alignment.data.dist.melt.meta <- plyr::join(TPA.alignment.data.dist.melt.meta,TPA.meta1.2.pairwise.t2, by="Taxa2", type="left")

Define comparisons

# Same sample
TPA.alignment.data.dist.melt.meta$same.sample <- ifelse(TPA.alignment.data.dist.melt.meta$Taxa1==TPA.alignment.data.dist.melt.meta$Taxa2,"same", "different")

# Years between samples
TPA.alignment.data.dist.melt.meta$year.distance <- abs(as.numeric(TPA.alignment.data.dist.melt.meta$Sample_Year.t1) - as.numeric(TPA.alignment.data.dist.melt.meta$Sample_Year.t2))
NAs introduced by coercionNAs introduced by coercion
# Same country
TPA.alignment.data.dist.melt.meta$same.country <- ifelse(TPA.alignment.data.dist.melt.meta$Geo_Country.t1 == TPA.alignment.data.dist.melt.meta$Geo_Country.t2, "same", "different")

# Same continent
TPA.alignment.data.dist.melt.meta$same.continent <- ifelse(TPA.alignment.data.dist.melt.meta$Continent.t1 == TPA.alignment.data.dist.melt.meta$Continent.t2, "same", "different")

# Same TPA Major Lineage
TPA.alignment.data.dist.melt.meta$same.TPA.majorlineage <- ifelse(TPA.alignment.data.dist.melt.meta$TPA.pinecone.major.t1==TPA.alignment.data.dist.melt.meta$TPA.pinecone.major.t2, "same", "different")
TPA.alignment.data.dist.melt.meta$same.TPA.majorlineage <- sapply(1:nrow(TPA.alignment.data.dist.melt.meta), function(x) ifelse((TPA.alignment.data.dist.melt.meta$TPA.pinecone.major.t1[x]=="0" | TPA.alignment.data.dist.melt.meta$TPA.pinecone.major.t2[x]=="0"),NA,TPA.alignment.data.dist.melt.meta$same.TPA.majorlineage[x]))

# Same TPA Lineage (cleaned up classifications)
TPA.alignment.data.dist.melt.meta$same.TPA.Lineage <- ifelse(TPA.alignment.data.dist.melt.meta$TPA_Lineage.t1==TPA.alignment.data.dist.melt.meta$TPA_Lineage.t2, "same", "different")
TPA.alignment.data.dist.melt.meta$same.TPA.Lineage <- sapply(1:nrow(TPA.alignment.data.dist.melt.meta), function(x) ifelse((TPA.alignment.data.dist.melt.meta$TPA_Lineage.t1[x]=="0" | TPA.alignment.data.dist.melt.meta$TPA_Lineage.t2[x]=="0"),NA,TPA.alignment.data.dist.melt.meta$same.TPA.Lineage[x]))


# Same TPA sublineage
TPA.alignment.data.dist.melt.meta$same.TPA.Pinecone.cluster <- ifelse(TPA.alignment.data.dist.melt.meta$TPA.pinecone.sublineage.t1==TPA.alignment.data.dist.melt.meta$TPA.pinecone.sublineage.t2,"same", "different")
TPA.alignment.data.dist.melt.meta$same.TPA.Pinecone.cluster <- sapply(1:nrow(TPA.alignment.data.dist.melt.meta), function(x) ifelse(((TPA.alignment.data.dist.melt.meta$same.sample[x]=="different" & TPA.alignment.data.dist.melt.meta$TPA.pinecone.sublineage.t1[x]=="Singleton") |(TPA.alignment.data.dist.melt.meta$same.sample[x]=="different" & TPA.alignment.data.dist.melt.meta$TPA.pinecone.sublineage.t2[x]=="Singleton")),"different",TPA.alignment.data.dist.melt.meta$same.TPA.Pinecone.cluster[x]))

# Country Comparisons label
TPA.alignment.data.dist.melt.meta$Country_combinations <- paste0(TPA.alignment.data.dist.melt.meta$Geo_Country.t1,"___",TPA.alignment.data.dist.melt.meta$Geo_Country.t2)

Do some analysis of SNP distances within each country


TPA.alignment.data.dist.melt.meta$Geo_Country.t1 <- factor(TPA.alignment.data.dist.melt.meta$Geo_Country.t1, levels=continental.country.cols.brew2$Geo_Country)

p.pairwise.snps.withinCountry <- ggplot(TPA.alignment.data.dist.melt.meta[(TPA.alignment.data.dist.melt.meta$same.country=="same" & TPA.alignment.data.dist.melt.meta$same.sample=="different"),], aes(Geo_Country.t1, Distance, color=Geo_Country.t1)) +
  geom_sina(alpha=0.25, scale='width', method="d") +
  theme_light() +
  theme.text.size + 
  #theme(axis.text.x = element_text(angle = -45, vjust = 0.5, hjust=0.1)) +
  x.theme.axis.rotate +
  labs(x="Country",y="Pairwise SNPs") +
  scale_color_manual(name="Country",values=continental.country.cols.brew2$country.col, breaks=continental.country.cols.brew2$Geo_Country) +
  theme(legend.key.size = unit(0.65,"line"),legend.position='right') + 
  ggtitle("Pairwise SNP distributions between samples from same countries") + 
  theme(plot.title = element_text(size = 10)) +
  NULL
p.pairwise.snps.withinCountry

Split up by Major Lineage

#TPA.alignment.data.dist.melt.meta[(TPA.alignment.data.dist.melt.meta$same.country=="same" & TPA.alignment.data.dist.melt.meta$same.sample=="different" & TPA.alignment.data.dist.melt.meta$same.TPA_Lineage=="same"),]

# Max pairwise distance within country and within Lineages
max(TPA.alignment.data.dist.melt.meta[(TPA.alignment.data.dist.melt.meta$same.country=="same" & TPA.alignment.data.dist.melt.meta$same.sample=="different" & TPA.alignment.data.dist.melt.meta$same.TPA.majorlineage=="same" & TPA.alignment.data.dist.melt.meta$TPA_Lineage.t1=="SS14"),"Distance"])
[1] 26
max(TPA.alignment.data.dist.melt.meta[(TPA.alignment.data.dist.melt.meta$same.country=="same" & TPA.alignment.data.dist.melt.meta$same.sample=="different" & TPA.alignment.data.dist.melt.meta$same.TPA.majorlineage=="same" & TPA.alignment.data.dist.melt.meta$TPA_Lineage.t1=="Nichols"),"Distance"])
[1] 80
p.pairwise.snps.withinCountry.within.Lineage <- ggplot(TPA.alignment.data.dist.melt.meta[(TPA.alignment.data.dist.melt.meta$same.country=="same" & TPA.alignment.data.dist.melt.meta$same.sample=="different" & TPA.alignment.data.dist.melt.meta$same.TPA.majorlineage=="same"),], aes(Geo_Country.t1, Distance, color=Geo_Country.t1)) +
  geom_sina(alpha=0.5, scale='width', method="d") +
  theme_light() +
  theme.text.size + 
  x.theme.axis.rotate +
  labs(x="Country",y="Pairwise SNPs") +
  scale_color_manual(name="Country",values=continental.country.cols.brew2$country.col, breaks=continental.country.cols.brew2$Geo_Country) +
  theme(legend.key.size = unit(0.65,"line"),legend.position='right') + 
  ggtitle("Pairwise SNP distributions between samples from same countries by lineage") + 
  theme(plot.title = element_text(size = 10)) +
  facet_grid(TPA_Lineage.t1~.) +
  theme(strip.background = element_rect(fill='white',linetype="solid"), strip.text.y = element_text(color = "grey25", size=10)) +
  NULL
p.pairwise.snps.withinCountry.within.Lineage

NA
NA

Do a combined plot (all, plus by major lineage)


TPA.alignment.data.dist.melt.meta.LineageCountryCombined <- TPA.alignment.data.dist.melt.meta[(TPA.alignment.data.dist.melt.meta$same.country=="same" & TPA.alignment.data.dist.melt.meta$same.sample=="different" & TPA.alignment.data.dist.melt.meta$same.TPA.majorlineage=="same"),c("Geo_Country.t1", "Distance","TPA_Lineage.t1")]
TPA.alignment.data.dist.melt.meta.LineageCountryCombined$TPA_Lineage <- TPA.alignment.data.dist.melt.meta.LineageCountryCombined$TPA_Lineage.t1

TPA.alignment.data.dist.melt.meta.LineageCountryCombined.2 <- TPA.alignment.data.dist.melt.meta[(TPA.alignment.data.dist.melt.meta$same.country=="same" & TPA.alignment.data.dist.melt.meta$same.sample=="different"),c("Geo_Country.t1", "Distance","TPA_Lineage.t1")]
TPA.alignment.data.dist.melt.meta.LineageCountryCombined.2$TPA_Lineage <- "All"


TPA.alignment.data.dist.melt.meta.LineageCountryCombined <- rbind(TPA.alignment.data.dist.melt.meta.LineageCountryCombined, TPA.alignment.data.dist.melt.meta.LineageCountryCombined.2)

p.pairwise.snps.withinCountry.within.all.Lineage <- ggplot(TPA.alignment.data.dist.melt.meta.LineageCountryCombined, aes(Geo_Country.t1, Distance, color=Geo_Country.t1)) +
  geom_sina(alpha=0.5, scale='width', method="d") +
  theme_light() +
  theme.text.size + 
  x.theme.axis.rotate +
  labs(x="Country",y="Pairwise SNPs") +
  scale_color_manual(name="Country",values=continental.country.cols.brew2$country.col, breaks=continental.country.cols.brew2$Geo_Country) +
  theme(legend.key.size = unit(0.65,"line"),legend.position='right') + 
  ggtitle("Pairwise SNP distributions among samples within the same country") +
  
  theme(plot.title = element_text(size = 10)) +
  facet_grid(TPA_Lineage~.) +
  theme(strip.background = element_rect(fill='white',linetype="solid"), strip.text.y = element_text(color = "grey25", size=10)) +
  NULL
p.pairwise.snps.withinCountry.within.all.Lineage

Look at pairwise distances between countries (e.g. minimum pairwise distance)

TPA.alignment.data.dist.melt.meta.between.countries <- TPA.alignment.data.dist.melt.meta[TPA.alignment.data.dist.melt.meta$same.country=="different",]

TPA.alignment.data.dist.melt.meta.between.countries.mindist <- TPA.alignment.data.dist.melt.meta.between.countries %>% 
  dplyr::group_by(Country_combinations) %>%
  summarise(min.dist=min(Distance))
`summarise()` ungrouping output (override with `.groups` argument)
TPA.alignment.data.dist.melt.meta.between.countries.mindist$Taxa1 <- gsub("\\_\\_\\_.+$","",TPA.alignment.data.dist.melt.meta.between.countries.mindist$Country_combinations, perl=T)
TPA.alignment.data.dist.melt.meta.between.countries.mindist$Taxa2 <- gsub("^.+\\_\\_\\_","",TPA.alignment.data.dist.melt.meta.between.countries.mindist$Country_combinations, perl=T)

TPA.alignment.data.dist.melt.meta.between.countries.mindist$log10.mindist <- log10(TPA.alignment.data.dist.melt.meta.between.countries.mindist$min.dist)

TPA.alignment.data.dist.melt.meta.between.countries.mindist$log2.mindist <- log2(TPA.alignment.data.dist.melt.meta.between.countries.mindist$min.dist)

TPA.alignment.data.dist.melt.meta.between.countries.mindist$Taxa1 <- factor(TPA.alignment.data.dist.melt.meta.between.countries.mindist$Taxa1, levels=continental.country.cols.brew2$Geo_Country)
TPA.alignment.data.dist.melt.meta.between.countries.mindist$Taxa2 <- factor(TPA.alignment.data.dist.melt.meta.between.countries.mindist$Taxa2, levels=continental.country.cols.brew2$Geo_Country)


#WGS.alignment.data.dist.melt.meta.between.countries.mindist.matrix <- dcast(WGS.alignment.data.dist.melt.meta.between.countries.mindist[,c(3,4,2)], taxa1~taxa2)

taxa1.pwise.country.cols <- unique(TPA.alignment.data.dist.melt.meta.between.countries.mindist$Taxa1)


p.country.minsnp.heatmap <- ggplot(TPA.alignment.data.dist.melt.meta.between.countries.mindist, aes(Taxa1, Taxa2, fill=min.dist)) +
  geom_tile(color="white") +
  scale_fill_gradient(low="yellow",high="red", trans="log2",name="Minimum Pairwise SNPs") + 
  #theme_classic() +
  theme_light() +
  theme.text.size + 
  scale_x_discrete(position = 'top') +
  #theme(axis.text.x=element_text(angle=90,hjust=0), axis.title.x = element_blank(),
  #      axis.title.y = element_blank()) +
  theme(axis.text.x=element_text(angle=90,vjust=1,hjust=0), axis.title.x = element_blank()) +
  geom_text(aes(label = min.dist), color = "black", size = 2.5) +
  #theme(axis.text.x = element_text(colour=data.frame(continental.country.cols.brew2)[continental.country.cols.brew2$Geo_Country!="Belgium","country.col"]), axis.text.y = element_text(colour=data.frame(continental.country.cols.brew2)[continental.country.cols.brew2$Geo_Country!="Belgium","country.col"])) +
  theme(axis.text.y = element_text(colour=data.frame(continental.country.cols.brew2)[continental.country.cols.brew2$Geo_Country!="Belgium","country.col"]))  +
  theme(legend.key.size = unit(0.65,"line"), legend.position='left') +
  #ggtitle("Minimum Pairwise SNPs between samples from different countries") +
  theme(plot.title = element_text(size = 10)) +
  theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank()) + 
  labs(y="Country") +
  NULL
Vectorized input to `element_text()` is not officially supported.
Results may be unexpected or may change in future versions of ggplot2.
p.country.minsnp.heatmap

Samples per country (high quality genomes) - needed to give some context to the heatmap plot

TPA.pinecone.genome.counts <- TPA.meta1.2.pinecone %>% dplyr::group_by(Geo_Country) %>%
  dplyr::summarise(Total_samples=n())
`summarise()` ungrouping output (override with `.groups` argument)
TPA.pinecone.genome.counts$Geo_Country <- factor(TPA.pinecone.genome.counts$Geo_Country, levels=continental.country.cols.brew2$Geo_Country)

p.hq.country.hbarplot <- ggplot(TPA.pinecone.genome.counts, aes(Total_samples,Geo_Country,fill=Geo_Country)) +
  geom_barh(stat="identity", position="stack", width=0.75) +
  geom_text(data=TPA.pinecone.genome.counts, aes((Total_samples+25), Geo_Country, label=Total_samples), size=2.5, inherit.aes = F) +
  #theme_classic() + 
  theme_light() +
  scale_x_continuous(breaks=c(0,100,200,300)) +
  coord_cartesian(xlim=c(0,275)) +
  theme.text.size + theme(legend.key.size = unit(0.65,"line"),legend.position='none') +
  scale_fill_manual(name="Country",values=continental.country.cols.brew2$country.col, breaks=continental.country.cols.brew2$Geo_Country) +
  labs(y="Country", x="Sample Count") +
  #theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank()) 
  NULL
#p.hq.country.hbarplot


p.hq.country.barplot <- ggplot(TPA.pinecone.genome.counts, aes(Geo_Country, Total_samples,fill=Geo_Country)) +
  geom_bar(stat="identity", position="stack", width=0.75) +
  geom_text(data=TPA.pinecone.genome.counts, aes(Geo_Country, (Total_samples+25), label=Total_samples), size=2.5, inherit.aes = F) +
  theme_light() +
  scale_y_continuous(breaks=c(0,100,200,300)) +
  coord_cartesian(ylim=c(0,275)) +
  theme.text.size + theme(legend.key.size = unit(0.65,"line"),legend.position='none') +
  scale_fill_manual(name="Country",values=continental.country.cols.brew2$country.col, breaks=continental.country.cols.brew2$Geo_Country) +
  labs(x="Country", y="Sample Count") +
  x.theme.axis.rotate +
  NULL
#p.hq.country.hbarplot

plot together

p.country.minsnp.heatmap.counts <- plot_grid(p.country.minsnp.heatmap, p.hq.country.hbarplot + y.theme.strip, align=T, ncol=2, rel_widths=c(5,1))
Transformation introduced infinite values in discrete y-axisTransformation introduced infinite values in discrete y-axisGraphs cannot be vertically aligned unless the axis parameter is set. Placing graphs unaligned.
p.country.minsnp.heatmap.counts 

Plot sina of within-country SNPs alongside heatmap of min-SNPs between countries

multicountry.pairwise.snps.grid <- plot_grid(p.pairwise.snps.withinCountry,p.country.minsnp.heatmap.counts, ncol=2, rel_widths=c(2,3), labels=c('D','E'), label_size=11)
multicountry.pairwise.snps.grid

Get combination details for all zero pairings

# ensure all possible combos are included by 2-siding
TPA.alignment.data.dist.melt.meta.between.countries.mindist.combinations <- rbind(data.frame(min.dist=TPA.alignment.data.dist.melt.meta.between.countries.mindist$min.dist, taxa1=TPA.alignment.data.dist.melt.meta.between.countries.mindist$Taxa1,taxa2=TPA.alignment.data.dist.melt.meta.between.countries.mindist$Taxa2, stringsAsFactors = F),data.frame(min.dist=TPA.alignment.data.dist.melt.meta.between.countries.mindist$min.dist, taxa1=TPA.alignment.data.dist.melt.meta.between.countries.mindist$Taxa2,taxa2=TPA.alignment.data.dist.melt.meta.between.countries.mindist$Taxa1, stringsAsFactors = F)) 
TPA.alignment.data.dist.melt.meta.between.countries.mindist.combinations <- unique(TPA.alignment.data.dist.melt.meta.between.countries.mindist.combinations)

TPA.alignment.data.dist.melt.meta.between.countries.mindist.combinations.zeros <- TPA.alignment.data.dist.melt.meta.between.countries.mindist.combinations[TPA.alignment.data.dist.melt.meta.between.countries.mindist.combinations$min.dist==0,]

TPA.alignment.data.dist.melt.meta.between.countries.mindist.combinations.zeros.combos <- TPA.alignment.data.dist.melt.meta.between.countries.mindist.combinations.zeros %>% dplyr::group_by(taxa1, taxa2) %>% dplyr::summarise(count=n())
`summarise()` regrouping output by 'taxa1' (override with `.groups` argument)
nrow(TPA.alignment.data.dist.melt.meta.between.countries.mindist.combinations.zeros.combos)/2
[1] 27
TPA.alignment.data.dist.melt.meta.between.countries.mindist.combinations.zeros.combos
NA

Get specific pairwise stats for UK and Canada


TPA.alignment.data.dist.melt.meta.UK.Canada <- (TPA.alignment.data.dist.melt.meta[(TPA.alignment.data.dist.melt.meta$Country_combinations=="UK___Canada" | TPA.alignment.data.dist.melt.meta$Country_combinations=="Canada___UK"),c("Taxa1","Taxa2","Distance", "Country_combinations","year.distance")])

# Number of comparisons
nrow(TPA.alignment.data.dist.melt.meta.UK.Canada[TPA.alignment.data.dist.melt.meta.UK.Canada$Distance==0,])
[1] 2622
Canada.UK.zero.comparison.samples <- as.character(unique(TPA.alignment.data.dist.melt.meta.UK.Canada[TPA.alignment.data.dist.melt.meta.UK.Canada$Distance==0,"Taxa1"]))
Canada.UK.zero.comparison.samples <- unique(c(Canada.UK.zero.comparison.samples,as.character(unique(TPA.alignment.data.dist.melt.meta.UK.Canada[TPA.alignment.data.dist.melt.meta.UK.Canada$Distance==0,"Taxa2"]))))

Canada.UK.zero.comparison.samples <- data.frame(Sample_Name=Canada.UK.zero.comparison.samples,stringsAsFactors = F)
Canada.UK.zero.comparison.samples <- plyr::join(Canada.UK.zero.comparison.samples,TPA.meta1.2, by="Sample_Name", type="left")

nrow(Canada.UK.zero.comparison.samples)
[1] 134
nrow(Canada.UK.zero.comparison.samples[Canada.UK.zero.comparison.samples$Geo_Country=="UK",])
[1] 78
nrow(Canada.UK.zero.comparison.samples[Canada.UK.zero.comparison.samples$Geo_Country=="Canada",])
[1] 56
# Look at temporal distance within zero-SNP comparisons between countries
sort(unique(TPA.alignment.data.dist.melt.meta.UK.Canada[TPA.alignment.data.dist.melt.meta.UK.Canada$Distance==0,"year.distance"]))
 [1]  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14
# Identify samples invovled in a 0 SNP comparison and are 14 years apart
unique(as.vector(as.matrix(TPA.alignment.data.dist.melt.meta.UK.Canada[(TPA.alignment.data.dist.melt.meta.UK.Canada$Distance==0 & TPA.alignment.data.dist.melt.meta.UK.Canada$year.distance==14),c("Taxa1","Taxa2")])))
[1] "TPA_UKBIR049" "TPA_UKBIR030" "TPA_BCC030"   "TPA_BCC032"   "TPA_UKMAN027" "TPA_UKLEE004"
TPA.meta1.2.pinecone[TPA.meta1.2.pinecone$Sample_Name %in% c("TPA_UKBIR049", "TPA_UKBIR030", "TPA_BCC030", "TPA_BCC032", "TPA_UKMAN027", "TPA_UKLEE004"),]

TPA.alignment.data.dist.melt.meta[(TPA.alignment.data.dist.melt.meta$Taxa1 %in% c("TPA_BCC030","TPA_BCC032") & TPA.alignment.data.dist.melt.meta$Taxa2 %in% c("TPA_BCC030","TPA_BCC032")),]
#"TPA_BCC030", "TPA_BCC032" 


min(Canada.UK.zero.comparison.samples[,"Sample_Year"])
[1] "2004"
max(Canada.UK.zero.comparison.samples[,"Sample_Year"])
[1] "2019"
TPA.alignment.data.dist.melt.meta

Make a plot looking at pairwise distances in UK and Canada

TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta <- (TPA.alignment.data.dist.melt.meta[(TPA.alignment.data.dist.melt.meta$Country_combinations=="Canada___UK" | TPA.alignment.data.dist.melt.meta$Country_combinations=="Canada___Canada" |  TPA.alignment.data.dist.melt.meta$Country_combinations=="UK___UK"),])

TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta <- TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta[TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta$same.sample=="different",]

TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta$Country_combinations2 <- gsub("UK___UK","England",gsub("Canada___Canada","British Columbia",gsub("Canada___UK","British Columbia v.s. England",TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta$Country_combinations)))


# do distributions plots on PW SNPs for country comparisons
p.UK.canada.pwSNPs.sina <- ggplot(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta, aes(Country_combinations2, Distance)) +
  geom_sina(alpha=0.1,size=1, aes(color=Country_combinations2)) + 
  #geom_boxplot(alpha=0.01, outlier.shape = NA, width=0.25) +
  theme_light() +
  theme.text.size + 
  #scale_y_log10() +
  labs(x="Country Combination",y="Pairwise SNPs") +
  #scale_colour_manual(values=c("#74C476", "cyan3", "#084594")) +
  scale_colour_manual(values=c("#74C476", "grey50", "#084594")) + 
  theme(legend.position='none') +
  ggtitle("Pairwise SNPs within and between British Columbia (Canada) and England (UK)") +
  NULL
p.UK.canada.pwSNPs.sina


# Do distributions of pwSNPs v.s. timepoints
p.UK.canada.pwSNPs.vs.Time.points <- ggplot(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta, aes(year.distance,Distance)) +
  geom_point(size=1, alpha=0.1) +
  geom_density_2d() +
  theme_light() +
  facet_grid(.~Country_combinations2) + 
  scale_y_log10() +
  labs(y="Pairwise SNP distance (log10 scale)", x="Pairwise time distance (years)") +
  theme.text.size +
  theme(strip.background = element_rect(fill='white',linetype="solid"), strip.text.x = element_text(color = "grey25", size=10))
#p.UK.canada.pwSNPs.vs.Time.points 

# Breakdown pairwise SNP/time distances by sublineage
TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta$TPA.pinecone.sublineage.t1 <- factor(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta$TPA.pinecone.sublineage.t1, levels=sublineages.cols.brew$sublineage)
p.UK.canada.pwSNPs.vs.Time.points.sublineage.breakdown <- ggplot(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta[TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta$same.TPA.Pinecone.cluster=="same",], aes(year.distance,Distance, color=TPA.pinecone.sublineage.t1)) +
  geom_point(size=2, alpha=0.25) +
  geom_density_2d(color="black", alpha=0.5) +
  theme_light() +
  facet_grid(TPA.pinecone.sublineage.t1~Country_combinations2) + 
  #scale_y_log10() +
  labs(y="Pairwise SNP distance (log10 scale)", x="Pairwise time distance (years)") +
  theme.text.size +
  theme(strip.background = element_rect(fill='white',linetype="solid"), strip.text.x = element_text(color = "grey25", size=10),strip.text.y = element_text(color = "grey25", size=10)) +
  scale_color_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) + 
  NULL
p.UK.canada.pwSNPs.vs.Time.points.sublineage.breakdown







# do pwSNPs v.s. timepoints using a hexplot to reduce overplotting
p.UK.canada.pwSNPs.vs.Time.hex <- ggplot(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta, aes(year.distance,Distance)) +
  stat_bin_hex(colour="white", na.rm=TRUE, bins = 20) +
  scale_fill_gradientn(colours=c("purple","green"), 
                       name = "Comparison Frequency", breaks=c(1,30,1000),
                       na.value=NA, trans="log10") + 
  facet_grid(.~Country_combinations2) + 
  theme_light() +
  labs(y="Pairwise SNP distance", x="Pairwise time distance (years)") +
  theme.text.size + theme(legend.key.size = unit(0.75,"line")) +
  theme(strip.background = element_rect(fill='white',linetype="solid"), strip.text.x = element_text(color = "grey25", size=10)) +
  theme(legend.position="bottom") +
  ggtitle("Pairwise SNPs and Years within and between British Columbia (Canada) and England (UK)") + theme(plot.title = element_text(size = 10))
#p.UK.canada.pwSNPs.vs.Time.hex




# do pwSNPs v.s. timepoints using a hexplot to reduce overplotting (by sublineage)
TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage <- TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta[TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta$same.TPA.Pinecone.cluster=="same",]

p.UK.canada.pwSNPs.vs.Time.hex.sublineage.breakdown <- ggplot(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage, aes(year.distance,Distance)) +
  stat_bin_hex(colour="white", na.rm=TRUE, bins = 15) +
  #geom_density_2d_filled() +
  #geom_density_2d_filled() + scale_fill_brewer(palette="PuRd") +
  scale_fill_gradientn(colours=c("purple","green"), 
                       name = "Comparison Frequency", breaks=c(1,30,1000),
                       na.value=NA, trans="log10") + 
  #geom_point(alpha=0.025, size=0.25) +
  #geom_density_2d(color="black", alpha=0.5, bins=4) +
  #facet_grid(TPA.pinecone.sublineage.t1~Country_combinations2) + 
  facet_grid(.~Country_combinations2) + 
  theme_light() +
  #scale_y_log10(breaks=c(0.01,1,5,10,20,40)) + scale_x_log10(breaks=c(0.01,1,5,10,20)) +
  #coord_cartesian(xlim=c(0.1,20), ylim=c(0.1,30)) +
  scale_y_continuous(breaks=seq(0,25,5)) +
  labs(y="Pairwise SNP distance", x="Pairwise time distance (years)") +
  theme.text.size + theme(legend.key.size = unit(0.75,"line")) +
  theme(strip.background = element_rect(fill='white',linetype="solid"), strip.text.x=element_text(color="grey25", size=10), strip.text.y=element_text(color="grey25", size=10)) +
  theme(legend.position="bottom") +
  ggtitle("Pairwise SNPs (same sublineage) and Years within and between British Columbia (Canada) and England (UK)") + theme(plot.title = element_text(size = 10))


p.UK.canada.pwSNPs.vs.Time.hex.sublineage.breakdown <- p.UK.canada.pwSNPs.vs.Time.hex.sublineage.breakdown + stat_smooth(method='lm', fullrange=F,se=T, color='black', level=95)
#p.UK.canada.pwSNPs.vs.Time.hex.sublineage.breakdown + stat_smooth(fullrange=F,se=T, color='black', formula=log10(x) ~ log10(x))
#p.UK.canada.pwSNPs.vs.Time.hex.sublineage.breakdown

Look at temporal relationships a little more

# time distances at 0 SNPs
mean(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage[TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage$Distance==0,"year.distance"])
[1] 2.452642
max(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage[TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage$Distance==0,"year.distance"])
[1] 15
min(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage[TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage$Distance==0,"year.distance"])
[1] 0
# mean SNP distance
max(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage$Distance)
[1] 26
# max SNP distance 
max(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage$Distance)
[1] 26
# time distances at 26 SNPs
mean(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage[TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage$Distance==26,"year.distance"])
[1] 1
max(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage[TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage$Distance==26,"year.distance"])
[1] 1
min(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage[TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage$Distance==26,"year.distance"])
[1] 1
# time distances at 0 SNPs (Canada)
mean(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage[(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage$Distance==0 & TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage$Country_combinations=="Canada___Canada"),"year.distance"])
[1] 2.8944
mean(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage[(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage$Distance==0 & TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage$Country_combinations=="UK___UK"),"year.distance"])
[1] 1.915912
mean(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage[(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage$Distance==0 & TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage$Country_combinations=="Canada___UK"),"year.distance"])
[1] 2.664378
##############
# SNP distances at 0 time
mean(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage[TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage$year.distance==0,"Distance"])
[1] 4.858593
max(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage[TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage$year.distance==0,"Distance"])
[1] 23
min(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage[TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage$year.distance==0,"Distance"])
[1] 0
max(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage$year.distance)
[1] 19
# SNP distances at 19 years time
mean(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage[TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage$year.distance==19,"Distance"])
[1] 7.8
max(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage[TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage$year.distance==19,"Distance"])
[1] 11
min(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage[TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage$year.distance==19,"Distance"])
[1] 6
# SNP distances at 0 time (England)
mean(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage[(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage$year.distance==0 & TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage$Country_combinations=="UK___UK"),"Distance"])
[1] 5.303675
# SNP distances at 0 time (Canada)
mean(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage[(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage$year.distance==0 & TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage$Country_combinations=="Canada___Canada"),"Distance"])
[1] 2.599581
# SNP distances at 0 time (Both)
mean(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage[(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage$year.distance==0 & TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage$Country_combinations=="Canada___UK"),"Distance"])
[1] 4.504094

Look at formally testing for signal

Calculate Pearson’s correlation (for real dataset)

nrow(TPA.alignment.data.dist.melt.meta.UK.Canada.fullmeta.within.sublineage)
[1] 55841

Combine pwSNP data with rest of Canada/UK plots


plot.UK.BC.stats.vs.bubbleplot <- plot_grid(plot.UK.BC.stats.combined + x.theme.strip + ggtitle("Syphilis Incidence and sublineage count") +theme(plot.title = element_text(size = 10)), plot.TPA.sublineage_UK.Canada.temporal.counts.bubbleplot + theme(legend.position="bottom",strip.background = element_blank(),strip.text.x = element_blank()), ncol=1, align=T, rel_heights=c(1,2), labels=c('A','B'), label_size=11)

#plot.UK.BC.stats.vs.bubbleplot_vs_pairwise.SNPs <- plot_grid(plot.UK.BC.stats.vs.bubbleplot, p.UK.canada.pwSNPs.vs.Time.hex, ncol=2, rel_widths=c(5,6), labels=c('','C'), label_size=11)

plot.UK.BC.stats.vs.bubbleplot_vs_pairwise.SNPs <- plot_grid(plot.UK.BC.stats.vs.bubbleplot, p.UK.canada.pwSNPs.sina, ncol=2, rel_widths=c(7,5), labels=c('','C'), label_size=11)



plot.UK.BC.stats.vs.bubbleplot_vs_pairwise.SNPs

Combine to make a BC vs UK only plot


#plot.UK.BC.stats.vs.bubbleplot
#p.UK.canada.pwSNPs.vs.Time.hex.sublineage.breakdown


#Cairo::Cairo(file=paste0(Figure_output_directory, "Supplementary_Figure13_Canada-vs-UK_distros_03-2021.svg"), width = 600, height = 1050,type="svg",units = "pt")
plot_grid(plot.UK.BC.stats.vs.bubbleplot, p.UK.canada.pwSNPs.sina, p.UK.canada.pwSNPs.vs.Time.hex.sublineage.breakdown, ncol=1, labels=c('','C','D'), label_size=11, scale=0.95, rel_heights=c(4,2,3))

#dev.off()

Combine Canada/UK analysis with Global Pairwise analysis



plot_grid(plot.UK.BC.stats.vs.bubbleplot_vs_pairwise.SNPs, multicountry.pairwise.snps.grid, ncol=1, scale=0.95)

Do pairwise SNPs within sublineages


#TPA.alignment.data.dist.melt.meta$Geo_Country.t1 <- factor(TPA.alignment.data.dist.melt.meta$Geo_Country.t1, levels=continental.country.cols.brew2$Geo_Country)

TPA.alignment.data.dist.melt.meta$TPA.pinecone.sublineage.t1 <- factor(TPA.alignment.data.dist.melt.meta$TPA.pinecone.sublineage.t1, levels=sublineages.cols.brew$sublineage)

#scale_color_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage)

p.pairwise.snps.within.Sublineage <- ggplot(TPA.alignment.data.dist.melt.meta[(TPA.alignment.data.dist.melt.meta$same.TPA.Pinecone.cluster=="same" & TPA.alignment.data.dist.melt.meta$same.sample=="different"),], aes(TPA.pinecone.sublineage.t1, Distance, color=TPA.pinecone.sublineage.t1)) +
  geom_violin(scale='width') +
  geom_sina(alpha=0.5, scale='width', method="d") + 
  theme_light() +
  theme.text.size + 
  #x.theme.axis.rotate +
  labs(x="Sublineage",y="Pairwise SNPs") +
  scale_color_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) +
  theme(legend.key.size = unit(0.65,"line"),legend.position='none') + 
  ggtitle("Pairwise SNP distributions between samples from same sublineage") + 
  theme(plot.title = element_text(size = 10)) + 
  NULL


p.pairwise.snps.within.Sublineage

Just check the maximum pairwise SNPs within sublineages

max(TPA.alignment.data.dist.melt.meta[(TPA.alignment.data.dist.melt.meta$same.TPA.Pinecone.cluster=="same" & TPA.alignment.data.dist.melt.meta$same.sample=="different"),"Distance"])
[1] 26
max(TPA.alignment.data.dist.melt.meta[(TPA.alignment.data.dist.melt.meta$same.TPA.Pinecone.cluster=="same" & TPA.alignment.data.dist.melt.meta$same.sample=="different" & TPA.alignment.data.dist.melt.meta$TPA.pinecone.sublineage.t1==19),"Distance"])
no non-missing arguments to max; returning -Inf
[1] -Inf

networks of lineage sharing

Create a network of country links (simply based on cooccurrence of sublineages) - make a heatmap based on the linklist


country.combinations <- data.frame(t(combn(data.frame(continental.country.cols.brew2)[continental.country.cols.brew2$Geo_Country!="Belgium","Geo_Country"],2, simplify=T)),stringsAsFactors = F)
colnames(country.combinations) <- c("taxa1","taxa2")
country.combinations <- rbind(country.combinations,data.frame(taxa1=country.combinations$taxa2, taxa2=country.combinations$taxa1, stringsAsFactors = F))
country.combinations$combo <- paste0(country.combinations$taxa1,"___",country.combinations$taxa2)


sublineage.country.summary.simple <- data.frame(TPA.meta1.2.pinecone[TPA.meta1.2.pinecone$TPA.pinecone.sublineage!="Singleton",] %>% dplyr::group_by(TPA.pinecone.sublineage,Geo_Country) %>% 
  dplyr::summarise(total.samples=n()), stringsAsFactors = F)
`summarise()` regrouping output by 'TPA.pinecone.sublineage' (override with `.groups` argument)
sublineage.country.summary.simple <- plyr::join(sublineage.country.summary.simple,unique(TPA.meta1.2.pinecone[,c("TPA.pinecone.sublineage","TPA.pinecone.major")]), by="TPA.pinecone.sublineage")


#sublineage.sharing.links.all <- sublineage.sharing.list
sublineage.sharing.links.all <- data.frame(sublineage.country.summary.simple %>% dplyr::group_by(TPA.pinecone.sublineage) %>% dplyr::summarise(no_links = length(TPA.pinecone.sublineage)),stringsAsFactors = F)
`summarise()` ungrouping output (override with `.groups` argument)
sublineage.sharing.links <- subset(sublineage.sharing.links.all, no_links>1)


# Make list of interaction combos (i.e. network edges)
linklist.all <- NULL
for (current in sublineage.sharing.links.all$TPA.pinecone.sublineage){
  current.sublineage <- subset(sublineage.country.summary.simple,TPA.pinecone.sublineage==current)
  if (nrow(current.sublineage)>1){
    current.sublineage1 <- data.frame(taxa1=t(combn(current.sublineage$Geo_Country, 2, FUN=NULL, simplify=T))[,1],taxa2=t(combn(current.sublineage$Geo_Country, 2, FUN=NULL, simplify=T))[,2],stringsAsFactors=T)
  current.sublineage1$sublineage <- current
  linklist.all <- rbind(linklist.all, current.sublineage1)
  }
}

linklist.all <- data.frame(linklist.all, stringsAsFactors=F)
linklist.all$combo <- paste0(linklist.all$taxa1,"___",linklist.all$taxa2)
linklist.all$combo2 <- paste0(linklist.all$taxa2,"___",linklist.all$taxa1)


linklist.all <- rbind(data.frame(taxa1=linklist.all$taxa1,taxa2=linklist.all$taxa2, sublineage=linklist.all$sublineage,combo=linklist.all$combo, stringsAsFactors =F), data.frame(taxa1=linklist.all$taxa2,taxa2=linklist.all$taxa1, sublineage=linklist.all$sublineage,combo=linklist.all$combo2, stringsAsFactors =F))


linklist.all.frequency <- linklist.all %>% dplyr::group_by(combo, .drop=F) %>%
  dplyr::summarise(Sublineage.Count=n())
`summarise()` ungrouping output (override with `.groups` argument)
linklist.all <- plyr::join(linklist.all,linklist.all.frequency, by="combo", type='left')

linklist.all2 <- plyr::join(country.combinations[,c("taxa1","taxa2","combo")],linklist.all[,c("taxa1","taxa2","combo","Sublineage.Count")], type="left")
Joining by: taxa1, taxa2, combo
linklist.all2 <- linklist.all2[rev(order(linklist.all2$combo, linklist.all2$Sublineage.Count)),]
linklist.all2 <-linklist.all2[!duplicated(linklist.all2),]
linklist.all <- linklist.all2


linklist.all[is.na(linklist.all$Sublineage.Count),"Sublineage.Count"] <- 0


linklist.all$taxa1 <- factor(linklist.all$taxa1, levels=continental.country.cols.brew2$Geo_Country)
linklist.all$taxa2 <- factor(linklist.all$taxa2, levels=continental.country.cols.brew2$Geo_Country)

p.country.sublineage.lings.heatmap <- ggplot(linklist.all, aes(taxa1, taxa2, fill=Sublineage.Count)) +
  geom_tile(color="white") +
  scale_fill_gradient(low="#ffffcc",high="#2c7fb8", name="Shared\nsublineages") + 
  #theme_classic() + 
  theme_light() + 
  theme.text.size + 
  theme(axis.text.x=element_text(angle=90,hjust=1,vjust=0.5), axis.title.x = element_blank(),
        axis.title.y = element_blank()) +
  geom_text(aes(label = Sublineage.Count), color = "black", size = 2.5) +
  theme(axis.text.x = element_text(colour=data.frame(continental.country.cols.brew2)[continental.country.cols.brew2$Geo_Country!="Belgium","country.col"]), axis.text.y = element_text(colour=data.frame(continental.country.cols.brew2)[continental.country.cols.brew2$Geo_Country!="Belgium","country.col"])) +
  theme(legend.key.size = unit(0.75,"line")) +
  theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank()) +
  ggtitle("Number of sublineages shared between countries") + theme(plot.title = element_text(size = 10))
Vectorized input to `element_text()` is not officially supported.
Results may be unexpected or may change in future versions of ggplot2.Vectorized input to `element_text()` is not officially supported.
Results may be unexpected or may change in future versions of ggplot2.
  
p.country.sublineage.lings.heatmap

Plot lineage sharing network with classified lineage counts


p.shared.sublineage.legend <- plot_grid(get_legend(plot.classified.sublineages.per.country + theme(legend.position='right')), get_legend(p.country.sublineage.lings.heatmap + theme(legend.position='right')), ncol=1, rel_heights=c(2,3))

p.shared.sublineage.plotgrid <-  plot_grid(plot.classified.sublineages.per.country + theme(legend.position="none") + ggtitle("Number of sublineages in each country") + theme(plot.title = element_text(size=10)) + x.theme.strip, p.country.sublineage.lings.heatmap + theme(legend.position="none"), align=T, ncol=1, rel_heights=c(2,3),labels=c('A','B'), label_size=11)

plot_grid(p.shared.sublineage.plotgrid,p.shared.sublineage.legend, ncol=2, rel_widths=c(4,1))

NA
NA

Try plot a different way (02-2021) to focus on global analysis alone


# Sort labels
plot.pairwise.SNPs.combi.5 <- plot_grid(plot.classified.sublineages.per.country + x.theme.strip + theme(legend.position="none") + labs(y="Sublineage Count"), p.hq.country.barplot + x.theme.strip + ggtitle('Sample count by country') + theme(plot.title=element_text(size=10)), 
                                        p.country.minsnp.heatmap + theme(legend.position="none") + ggtitle('Minimum pairwise SNP distance between countries') + theme(plot.title=element_text(size=10)), ncol=1, rel_heights=c(1,1,4), align="v", axis="lr", labels=c('A','B','D'), label_size=11)

plot.pairwise.SNPs.combi.5 <- plot_grid(plot.pairwise.SNPs.combi.5, p.pairwise.snps.withinCountry.within.all.Lineage + theme(legend.position='none'), ncol=2, labels=c('','C'), label_size=11, scale=0.95)



# Sort labels
plot.pairwise.SNPs.combi.6 <- plot_grid(plot.classified.sublineages.per.country + x.theme.strip + theme(legend.position="none") + labs(y="Sublineage Count"), p.hq.country.barplot + ggtitle('Sample count by country') + theme(plot.title=element_text(size=10)), 
                                        p.country.minsnp.heatmap + theme(legend.position="none") + ggtitle('Minimum pairwise SNP distance between countries') + theme(plot.title=element_text(size=10)), ncol=1, rel_heights=c(1,2,4), align="v", axis="lr", labels=c('A','B','D'), label_size=11)

plot.pairwise.SNPs.combi.6 <- plot_grid(plot.pairwise.SNPs.combi.6, p.pairwise.snps.withinCountry.within.all.Lineage + theme(legend.position='none'), ncol=2, labels=c('','C'), label_size=11, scale=0.95)




pwSNPs.legend <- get_legend(p.pairwise.snps.withinCountry.within.all.Lineage + theme(legend.position='top'))
pwSNPs.heatmap.legend <- get_legend(p.country.minsnp.heatmap + theme(legend.position='top'))
sublineages.legend <- get_legend(plot.classified.sublineages.per.country + theme(legend.position='top') + guides(fill=guide_legend(nrow=3)))
countries.bar.legend <- get_legend(p.hq.country.barplot + theme(legend.position='top') + guides(fill=guide_legend(nrow=6)))

Figure3.combi.legend <- plot_grid(sublineages.legend,pwSNPs.heatmap.legend,countries.bar.legend, nrow=1, rel_widths=c(2,1,3))

pwSNPs.legend.vert <- get_legend(p.pairwise.snps.withinCountry.within.all.Lineage + theme(legend.position='left'))
pwSNPs.heatmap.legend.vert <- get_legend(p.country.minsnp.heatmap + theme(legend.position='left'))
sublineages.legend.vert <- get_legend(plot.classified.sublineages.per.country + theme(legend.position='left') + guides(fill=guide_legend(ncol=1)))
countries.bar.legend.vert <- get_legend(p.hq.country.barplot + theme(legend.position='left') + guides(fill=guide_legend(ncol=1)))

Figure3.combi.legend.vert <- plot_grid(sublineages.legend.vert,pwSNPs.heatmap.legend.vert,countries.bar.legend.vert, ncol=1, rel_heights=c(2,1,3))



####
# Version 7 of this complex and much commented on plot ;-) 

Figure3.combi.legend.mixit1 <- plot_grid(sublineages.legend,countries.bar.legend, nrow=2, rel_heights=c(2,3))

# Sort Figure and labels
plot.pairwise.SNPs.combi.7 <- plot_grid(plot.classified.sublineages.per.country + x.theme.strip + theme(legend.position="none") + labs(y="Sublineage Count"), p.hq.country.barplot + x.theme.strip + ggtitle('Sample count by country') + theme(plot.title=element_text(size=10)), 
                                        p.country.minsnp.heatmap + theme(legend.position="none") + ggtitle('Minimum pairwise SNP distance between countries') + theme(plot.title=element_text(size=10)), ncol=1, rel_heights=c(1,1,4), align="v", axis="lr", labels=c('A','B','D'), label_size=11)
plot.pairwise.SNPs.combi.7.a <- plot_grid(plot.pairwise.SNPs.combi.7, pwSNPs.heatmap.legend, rel_heights=c(11,1),ncol=1)

plot.pairwise.SNPs.combi.7.b <- plot_grid(Figure3.combi.legend.mixit1,p.pairwise.snps.withinCountry.within.all.Lineage + theme(legend.position='none'),ncol=1, rel_heights=c(1,4), labels=c('','C'), label_size=11, scale=0.95)  

plot.pairwise.SNPs.combi.7.c <- plot_grid(plot.pairwise.SNPs.combi.7.a, plot.pairwise.SNPs.combi.7.b, ncol=2)






#Cairo::Cairo(file=paste0(Figure_output_directory, "Figure4_Sublin+PairwiseSNPs__Global-distro_02-2021.svg"), width = 800, height = 800,type="svg",units = "pt")
plot.pairwise.SNPs.combi.7.c

#dev.off()


# need to do a tree that only highlights singleton or private sublineages


private.singleton.lineages <- data.frame(Private.country.counts[Private.country.counts$private.distro=="private",c("TPA.pinecone.sublineage","private.distro")])

private.singleton.lineages <- rbind(private.singleton.lineages,data.frame(TPA.pinecone.sublineage="Singleton",private.distro="Singleton",stringsAsFactors = F))
private.singleton.lineages$private.sublineages <- private.singleton.lineages$TPA.pinecone.sublineage
private.singleton.lineages <- private.singleton.lineages[,c("TPA.pinecone.sublineage","private.sublineages")]

private.singleton.samples <-  plyr::join(TPA.meta1.2.pinecone[,c("Sample_Name","TPA.pinecone.sublineage")],private.singleton.lineages, type="left", by="TPA.pinecone.sublineage")

private.singleton.samples <- data.frame(row.names=private.singleton.samples$Sample_Name, "Private or Singleton\nSublineage"=private.singleton.samples$private.sublineages)


# add private lineage strip to tree 
p.TPA.MLtree.sublineages.privatelineage <- gheatmap(TPA.MLtree.ggtree.tippoint + theme(legend.position="none"),
               private.singleton.samples, color='grey70',width=0.075,offset=0.00000725, colnames_angle=-45,colnames_offset_y=0, hjust=0,font.size=2) + 
  scale_fill_manual(name="Private & Singleton\nSublineages",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) +
  theme.text.size + theme(legend.key.size = unit(0.65,"line"),legend.position='right')
p.TPA.MLtree.sublineages.privatelineage <- p.TPA.MLtree.sublineages.privatelineage + new_scale_fill()


p.TPA.MLtree.sublineages.privatelineage <-gheatmap(p.TPA.MLtree.sublineages.privatelineage,TPA.rawseq.countries.p, color='grey70',width=0.075,offset=0.00001725, colnames_angle=-45,colnames_offset_y=0, hjust=0,font.size=2) + 
  scale_fill_manual(name="Country",values=continental.country.cols.brew2$country.col, breaks=continental.country.cols.brew2$Geo_Country) +
  theme.text.size + theme(legend.key.size = unit(0.65,"line"),legend.position='right') +
  NULL



#Cairo::Cairo(file=paste0(Figure_output_directory, "Supplementary_Figure11__MLtree_private+singleton_02-2021.svg"), width = 800, height = 800,type="svg",units = "pt")
p.TPA.MLtree.sublineages.privatelineage

#dev.off()

Need to make a subtree highlighting the Reference strains from Nichols lineage

#Nichols.coll + geom_text2(aes(subset=!isTip, label=node), hjust=-.3, size=2.5) 
#ggtree(Nichols.ref.subtree.nodeid.tree) + geom_text2(aes(subset=!isTip, label=node), hjust=-.3) 

#Nichols.reference.clade.Year.data <- data.frame(row.names=TPA.meta1.2.pinecone.havedates$Sample_Name, TPA.meta1.2.pinecone.havedates$Sample_Year,stringsAsFactors=F)


Nichols.ref.subtree.nodeid <- 976
#Nichols.ref.subtree.nodeid <- 979

Nichols.ref.subtree.nodeid.tree <- tree_subset(TPA.MLtree, node=Nichols.ref.subtree.nodeid,levels_back=0)
#ggtree(Nichols.ref.subtree.nodeid.tree) + geom_tiplab(size=2.5) 



p.Nichols.ref.subtree.nodeid.tree <- ggtree(Nichols.ref.subtree.nodeid.tree) %<+% data.frame(Sample_Name=TPA.meta1.2.pinecone$Sample_Name, Sublineage=TPA.meta1.2.pinecone$TPA.pinecone.sublineage) + 
  geom_tippoint(aes(color=Sublineage), size=2.5, alpha=0.25,show.legend=F) + 
  scale_color_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) +
  # add bootstrap support
  geom_point2(aes(subset=(!isTip & as.numeric(label)>95)),size=2, shape=18) +
  geom_tiplab(size=2.5,align=F) + 
  geom_treescale(fontsize = 2.5, x=0.00001, y=12) +
  #xlim(0, 0.00007) +
  NULL

p.Nichols.ref.subtree.nodeid.tree.hm <- gheatmap(p.Nichols.ref.subtree.nodeid.tree,
               data.frame(row.names=TPA.meta1.2.pinecone$Sample_Name, Sublineage=TPA.meta1.2.pinecone$TPA.pinecone.sublineage), color=NULL,width=0.065,offset=0.0000095, colnames_angle=0,colnames_offset_y=-0.01, font.size=2) + 
  scale_fill_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) +
  theme.text.size + theme(legend.key.size = unit(0.75,"line"),legend.position='right') +
  geom_rootedge(0.00000075) 
Scale for 'fill' is already present. Adding another scale for 'fill', which will replace the existing scale.
p.Nichols.ref.subtree.nodeid.tree.hm <- p.Nichols.ref.subtree.nodeid.tree.hm + new_scale_fill()


p.Nichols.ref.subtree.nodeid.tree.hm <- gheatmap(p.Nichols.ref.subtree.nodeid.tree.hm, data.frame(row.names=TPA.meta1.2.pinecone$Sample_Name, Year=TPA.meta1.2.pinecone$Sample_5year.window, stringsAsFactors = F), color=NULL,width=0.065,offset=0.0000135, colnames_angle=0,colnames_offset_y=-0.01, font.size=2) + scale_fill_manual(name="Year",values=TPA.5year.window.brewcols$window.5year.cols[1:(length(TPA.5year.window.brewcols$window.5year.cols)-1)], breaks=TPA.5year.window.brewcols$window.5year[1:(length(TPA.5year.window.brewcols$window.5year)-1)]) #+
Scale for 'fill' is already present. Adding another scale for 'fill', which will replace the existing scale.
  #theme.text.size + theme(legend.key.size = unit(0.75,"line"),legend.position='left')


p.Nichols.ref.subtree.nodeid.tree.hm <- p.Nichols.ref.subtree.nodeid.tree.hm + new_scale_fill()
p.Nichols.ref.subtree.nodeid.tree.hm

NA
NA

Plot main Nichols tree, but with highlight for relevant clade

p.TPA.Nichols.coll.highlight <- p.TPA.Nichols.coll + new_scale_fill()
p.TPA.Nichols.coll.highlight <- p.TPA.Nichols.coll.highlight  + geom_hilight(node=Nichols.ref.subtree.nodeid, alpha=0.2, fill="grey45")
#p.TPA.Nichols.coll.highlight

# Add sample year (group)
p.TPA.Nichols.coll.highlight <- gheatmap(p.TPA.Nichols.coll.highlight,data.frame(row.names=TPA.meta1.2.pinecone$Sample_Name, Year=TPA.meta1.2.pinecone$Sample_5year.window, stringsAsFactors = F), color=NULL,width=0.085,offset=0.00002025, colnames_angle=0,colnames_offset_y=-1, font.size=2) + scale_fill_manual(name="Year",values=TPA.5year.window.brewcols$window.5year.cols[1:(length(TPA.5year.window.brewcols$window.5year.cols)-1)], breaks=TPA.5year.window.brewcols$window.5year[1:(length(TPA.5year.window.brewcols$window.5year)-1)]) +
  theme.text.size + theme(legend.key.size = unit(0.65,"line"),legend.position='left')
Scale for 'fill' is already present. Adding another scale for 'fill', which will replace the existing scale.
p.TPA.Nichols.coll.highlight <- p.TPA.Nichols.coll.highlight + new_scale_fill()

plot Nichols trees together


p.Nichols.ref.subtree.nodeid.tree.hm.grid <- plot_grid(NULL,p.Nichols.ref.subtree.nodeid.tree.hm + theme(legend.position="none") + ggtitle("Subtree") + theme(plot.title = element_text(size = 10)), NULL, rel_heights=c(1,4,1),ncol=1, labels=c('','B',''), label_size=11, vjust=0)

p.Nichols.ref.subtree.nodeid.tree.hm.grid.final <- plot_grid(p.TPA.Nichols.coll.highlight + theme(legend.position="left") + ggtitle("Nichols-lineage phylogeny") + theme(plot.title = element_text(size = 10)),NULL,p.Nichols.ref.subtree.nodeid.tree.hm.grid, ncol=3, rel_widths=c(10,1,10), labels=c('A','',''), vjust=1, label_size=11)


#Cairo::Cairo(file=paste0(Figure_output_directory, "Supplementary_Figure6_MLtree_Nichols-reference-highlight__02-2021.svg"), width = 800, height = 500,type="svg",units = "pt")
p.Nichols.ref.subtree.nodeid.tree.hm.grid.final

#dev.off()

subset Nichols to show outgroups better


# sublineage 19 
sublineages.tocollapse.nodeid.19 <- 997
# Sublineage 14 (formerly called 19 in older analysis before bootstrapping)
sublineages.tocollapse.nodeid.14 <- 997

# sublineage 12 
sublineages.tocollapse.nodeid.12 <- 963



# Collapse SS14 clade and largest Nichols sublineage to make for easier viewing
Nichols.coll.2clades <- ggtree(TPA.MLtree) %>% collapse(node=SS14.subtree.nodeid) %>% 
  collapse(node=sublineages.tocollapse.nodeid.19) #%>%
  #collapse(node=sublineages.tocollapse.nodeid.12) 

# Add some extra to y axis for spacing
Nichols.coll.2clades$data[Nichols.coll.2clades$data$node==SS14.subtree.nodeid,"y"] <- Nichols.coll.2clades$data[Nichols.coll.2clades$data$node==SS14.subtree.nodeid,"y"] + 8

Nichols.coll.2clades$data[Nichols.coll.2clades$data$node==sublineages.tocollapse.nodeid.14,"y"] <- Nichols.coll.2clades$data[Nichols.coll.2clades$data$node==sublineages.tocollapse.nodeid.14,"y"] + 3

#Nichols.coll.2clades$data[Nichols.coll.2clades$data$node==sublineages.tocollapse.nodeid.12,"y"] <- Nichols.coll.2clades$data[Nichols.coll.2clades$data$node==sublineages.tocollapse.nodeid.12,"y"] + 5
#sublineages.tocollapse.nodeid.12


# Add first triangle
Nichols.coll.2clades <- Nichols.coll.2clades + geom_text2(aes(subset=(node == SS14.subtree.nodeid)), size=20, label=intToUtf8(9664), hjust=0.2,vjust=.55, family="OpenSansEmoji", color="indianred1", alpha=.75)
Nichols.coll.2clades <- Nichols.coll.2clades  + geom_text2(aes(subset=(node == SS14.subtree.nodeid)), cex=2.5, vjust=0.2, label="SS14",hjust = -1.5)


# Add second triangle
#Nichols.coll.2clades <- Nichols.coll.2clades + geom_text2(aes(subset=(node == sublineages.tocollapse.nodeid.19)), size=20, label=intToUtf8(9664), hjust=0.2,vjust=.55, family="OpenSansEmoji", color=sublineages.cols.brew[sublineages.cols.brew$sublineage==19,"sublineage.cols"], alpha=.75)
#Nichols.coll.2clades <- Nichols.coll.2clades  + geom_text2(aes(subset=(node == sublineages.tocollapse.nodeid.19)), cex=2.5, vjust=0.2, label="Sublineage 19",hjust = -0.5)

Nichols.coll.2clades <- Nichols.coll.2clades + geom_text2(aes(subset=(node == sublineages.tocollapse.nodeid.14)), size=20, label=intToUtf8(9664), hjust=0.2,vjust=.55, family="OpenSansEmoji", color=sublineages.cols.brew[sublineages.cols.brew$sublineage==14,"sublineage.cols"], alpha=.75)
Nichols.coll.2clades <- Nichols.coll.2clades  + geom_text2(aes(subset=(node == sublineages.tocollapse.nodeid.14)), cex=2.5, vjust=0.2, label="Sublineage 14",hjust = -0.5)



p.Nichols.coll.2clades <- Nichols.coll.2clades %<+% data.frame(Sample_Name=TPA.meta1.2.pinecone$Sample_Name, Sublineage=TPA.meta1.2.pinecone$TPA.pinecone.sublineage) +
  geom_tippoint(aes(color=Sublineage), size=2.5, alpha=0.25,show.legend=F) + 
  scale_color_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) +
  # add bootstrap support
  geom_point2(aes(subset=(!isTip & as.numeric(label)>95)),size=2, shape=18) +
  geom_tiplab(size=2.5,align=F) + 
  geom_treescale(fontsize = 2.5, x=0.00001, y=25) + 
  geom_tiplab(size=2.5) + 
  geom_hilight(node=1055, alpha=0.25, fill=sublineages.cols.brew[sublineages.cols.brew$sublineage==6,"sublineage.cols"]) +
  geom_hilight(node=957, alpha=0.25, fill=sublineages.cols.brew[sublineages.cols.brew$sublineage==7,"sublineage.cols"])

p.Nichols.coll.2clades <- p.Nichols.coll.2clades + new_scale_fill()

p.Nichols.coll.2clades.hm <- gheatmap(p.Nichols.coll.2clades,
               data.frame(row.names=TPA.meta1.2.pinecone$Sample_Name, Sublineage=TPA.meta1.2.pinecone$TPA.pinecone.sublineage), color=NULL,width=0.06,offset=0.0000095, colnames_angle=0,colnames_offset_y=-0.01, font.size=2.25) + 
  scale_fill_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) +
  theme.text.size + theme(legend.key.size = unit(0.65,"line"),legend.position='right')

p.Nichols.coll.2clades.hm <- p.Nichols.coll.2clades.hm + new_scale_fill()

p.Nichols.coll.2clades.hm <- gheatmap(p.Nichols.coll.2clades.hm,TPA.rawseq.countries.p, color=NULL,width=0.06,offset=0.0000165, colnames_angle=0,colnames_offset_y=-0.01, font.size=2.25) + 
  scale_fill_manual(name="Country",values=continental.country.cols.brew2$country.col, breaks=continental.country.cols.brew2$Geo_Country) +
  theme.text.size + theme(legend.key.size = unit(0.65,"line"),legend.position='bottom') + 
  #geom_treescale(fontsize = 2.5, x=0.000001, y=35) +
  NULL
p.Nichols.coll.2clades.hm <- p.Nichols.coll.2clades.hm + new_scale_fill()


p.Nichols.coll.2clades.hm <- gheatmap(p.Nichols.coll.2clades.hm, data.frame(row.names=TPA.meta1.2.pinecone$Sample_Name, Year=TPA.meta1.2.pinecone$Sample_5year.window, stringsAsFactors = F), color=NULL,width=0.06,offset=0.0000235, colnames_angle=0,colnames_offset_y=-0.01, font.size=2.25) + scale_fill_manual(name="Year",values=TPA.5year.window.brewcols$window.5year.cols[1:(length(TPA.5year.window.brewcols$window.5year.cols)-1)], breaks=TPA.5year.window.brewcols$window.5year[1:(length(TPA.5year.window.brewcols$window.5year)-1)]) +
  theme.text.size + theme(legend.key.size = unit(0.65,"line"),legend.position='left') + 
  ylim(-1,57)

p.TPA.Nichols.coll.highlight <- p.TPA.Nichols.coll.highlight + new_scale_fill()



#Cairo::Cairo(file=paste0(Figure_output_directory, "Supplementary_Figure5_MLtree_highlight-outgroups__02-2021.svg"), width = 700, height = 500,type="svg",units = "pt")
p.Nichols.coll.2clades.hm + ggtitle("Nichols-lineage phylogeny with collapsed nodes") + theme(plot.title = element_text(size = 10))

#dev.off()

Subset SS14 tree to show outgroups


#SS14.coll + geom_text2(aes(subset=!isTip, label=node), hjust=-.3, size=2.5)

#ss14.sublin2.collapse.node <- 542
ss14.sublin1.collapse.node <- 534 #535

SS14.subclades1 <- ggtree(TPA.MLtree) %>% collapse(node=Nichols.subtree.nodeid) %>% 
  collapse(node=ss14.sublin1.collapse.node)
# Add some extra to y axis for spacing
SS14.subclades1$data[SS14.subclades1$data$node==Nichols.subtree.nodeid,"y"] <- SS14.subclades1$data[SS14.subclades1$data$node==Nichols.subtree.nodeid,"y"] -5

SS14.subclades1$data[SS14.subclades1$data$node==ss14.sublin1.collapse.node,"y"] <- SS14.subclades1$data[SS14.subclades1$data$node==ss14.sublin1.collapse.node,"y"] + 2

# Add first triangle
SS14.subclades1 <- SS14.subclades1 + geom_text2(aes(subset=(node == Nichols.subtree.nodeid)), size=20, label=intToUtf8(9664), hjust=0.2,vjust=.55, family="OpenSansEmoji", color="royalblue2", alpha=.75)
SS14.subclades1 <- SS14.subclades1 + geom_text2(aes(subset=(node == Nichols.subtree.nodeid)), cex=2.5, vjust=0.2, label="Nichols",hjust = -1.25)
# Add second triangle
SS14.subclades1 <- SS14.subclades1 + geom_text2(aes(subset=(node == ss14.sublin1.collapse.node)), size=20, label=intToUtf8(9664), hjust=0.2,vjust=.55, family="OpenSansEmoji", color=sublineages.cols.brew[sublineages.cols.brew$sublineage==1,"sublineage.cols"], alpha=.75)
SS14.subclades1 <- SS14.subclades1 + geom_text2(aes(subset=(node == ss14.sublin1.collapse.node)), cex=2, vjust=0.2, label="Sublineage 1",hjust = -0.75)


# add tippoint colours (sublineage)
p.SS14.subclades1 <- SS14.subclades1 %<+% data.frame(Sample_Name=TPA.meta1.2.pinecone$Sample_Name, Sublineage=TPA.meta1.2.pinecone$TPA.pinecone.sublineage) +
  geom_tippoint(aes(color=Sublineage), size=1.5, alpha=0.25,show.legend=F) + 
  scale_color_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) +
  # add bootstrap support
  geom_point2(aes(subset=(!isTip & as.numeric(label)>95)),size=2, shape=18) +
  geom_treescale(fontsize = 2.5, x=0.00001, y=25)  
p.SS14.subclades1 <- p.SS14.subclades1 + new_scale_fill()

# add heatmap strips (sublineage)
p.SS14.subclades1.hm <- gheatmap(p.SS14.subclades1,
               data.frame(row.names=TPA.meta1.2.pinecone$Sample_Name, Sublineage=TPA.meta1.2.pinecone$TPA.pinecone.sublineage), color=NULL,width=0.06,offset=0.0000095, colnames_angle=0,colnames_offset_y=-0.01, font.size=2.25) + 
  scale_fill_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) +
  theme.text.size + theme(legend.key.size = unit(0.65,"line"),legend.position='right')
p.SS14.subclades1.hm <- p.SS14.subclades1.hm + new_scale_fill()

# add heatmap strips (country)
p.SS14.subclades1.hm <- gheatmap(p.SS14.subclades1.hm,TPA.rawseq.countries.p, color=NULL,width=0.06,offset=0.0000155, colnames_angle=0,colnames_offset_y=-0.01, font.size=2.25) + 
  scale_fill_manual(name="Country",values=continental.country.cols.brew2$country.col, breaks=continental.country.cols.brew2$Geo_Country) +
  theme.text.size + theme(legend.key.size = unit(0.65,"line"),legend.position='bottom') +
  geom_tiplab(size=2) +
  NULL
p.SS14.subclades1.hm <- p.SS14.subclades1.hm + new_scale_fill()

# Add year group
p.SS14.subclades1.hm <- gheatmap(p.SS14.subclades1.hm,data.frame(row.names=TPA.meta1.2.pinecone$Sample_Name, Year=TPA.meta1.2.pinecone$Sample_5year.window, stringsAsFactors = F), color=NULL,width=0.065,offset=0.0000215, colnames_angle=0,colnames_offset_y=-0.01, font.size=2.25) + scale_fill_manual(name="Year",values=TPA.5year.window.brewcols$window.5year.cols[1:(length(TPA.5year.window.brewcols$window.5year.cols)-1)], breaks=TPA.5year.window.brewcols$window.5year[1:(length(TPA.5year.window.brewcols$window.5year)-1)]) +
  theme.text.size + theme(legend.key.size = unit(0.65,"line"),legend.position='left') +
  ylim(-6,67) #ylim(-6,115)  
p.SS14.subclades1.hm <- p.SS14.subclades1.hm + new_scale_fill()


#Cairo::Cairo(file=paste0(Figure_output_directory, "Supplementary_Figure4_MLtree_highlight-SS14__02-2021.svg"), width = 700, height = 800,type="svg",units = "pt")
p.SS14.subclades1.hm + ggtitle("SS14-lineage phylogeny") + theme(plot.title=element_text(size = 10))

#dev.off()




BEAST analysis



Subsampling representative tree for BEAST analyis


Country.list2 <- data.frame(continental.country.cols.brew2,stringsAsFactors = F)[continental.country.cols.brew2$Geo_Country!="Belgium","Geo_Country"]
sublineage.lineage.list2 <- sublineages.cols.brew[sublineages.cols.brew$sublineage!="Singleton","sublineage"]
#Full.samplelist2 <- TPA.meta1.2.pinecone$Sample_Name
Full.samplelist2 <- TPA.meta1.2.pinecone[((TPA.meta1.2.pinecone$Sample_Year!="-") & !grepl("Nichols",TPA.meta1.2.pinecone$Sample_Name) & !grepl("-",TPA.meta1.2.pinecone$Sample_Year)),"Sample_Name"]
TPA.meta1.2.pinecone.havedates <- TPA.meta1.2.pinecone[TPA.meta1.2.pinecone$Sample_Name %in% Full.samplelist2,]


mysamplesize <- 5
total.bootstraps <- 1

all.bootstraps.lists <- NULL
all.bootstraps.trees <- c(rtree(20)) # create with random start tree to force into a multiphylo object
current.bootstrap <- 0
repeat {
  country.sample <- NULL
  for (current.lineage in sublineage.lineage.list2){
    for (current.country in Country.list2){
      current.list <- TPA.meta1.2.pinecone.havedates[(TPA.meta1.2.pinecone.havedates$TPA.pinecone.sublineage==current.lineage & TPA.meta1.2.pinecone.havedates$Geo_Country==current.country),"Sample_Name"]
      current.list <- current.list[!is.na(current.list)]
      if (length(current.list)>1){
        current.sample <- unique(sample(current.list,size=mysamplesize, replace=T))
        country.sample <- c(as.vector(current.sample), country.sample)
      }
    }
  }
  country.sample <- c(country.sample, as.vector(TPA.meta1.2.pinecone.havedates[(TPA.meta1.2.pinecone.havedates$TPA.pinecone.sublineage=="Singleton"),"Sample_Name"]))
  
  current.bootstrap <- current.bootstrap + 1
  current.sample.tree <- (ape::keep.tip(TPA.MLtree, country.sample))
  all.bootstraps.trees <- c(all.bootstraps.trees,c(current.sample.tree),recursive=T)
  all.bootstraps.lists <- c(all.bootstraps.lists, list(country.sample))
  if (current.bootstrap == total.bootstraps){
    break
  }
}
all.bootstraps.trees <- all.bootstraps.trees[c(2:(total.bootstraps+1))] # remove random start tree

#all.bootstraps.trees[[1]]
#subsampled.ML.tips.6pCountry.pSublin <- all.bootstraps.trees[[1]]$tip.label

# Outputs from a previous random loop used below to ensure sample remains the same
subsampled.ML.tips.6pCountry.pSublin <- c("Mexico_A-mcf", "TPA_RUS_Tuva-62", "TPA_RUS_Tuva-58", "TPA_RUS_Tuva-59", "TPA_RUS_Tuva-61", "PHE140073A", "UW116B", "UW186B", "UW213B", "PHE150137A", "PHE150129A", "TPA_UKBRG017", "TPA_BCC161", "TPA_OMI006", "TPA_ALC105", "UW187B", "PHE150177A", "TPA_BCC085", "K3", "SHE_V", "C3", "Q3", "TPA_BCC075", "TPA_USL-BAL-2", "SS14_v2", "UW824B", "PHE140084A", "TPA_HUN200024", "TPA_HUN190022", "TPA_UKBRG004", "TPA_HUN190008", "UW099B", "TPA_USL-SEA-81-8", "TPA_ZIM025", "TPA_ZIM005", "TPA_ZIM009", "TPA_ZIM007", "UW262B", "UW391B", "TPA_BCC139", "TPA_BCC137", "TPA_UKBRG015", "TPA_UKBRG018", "PHE130041A", "TPA_BCC130", "UW376B", "PHE150159A", "UW244B", "UW291B", "TPA_BCC125", "PT_SIF1002", "PT_SIF1196", "PT_SIF0857", "PHE160254A", "PT_SIF1183", "PHE160249A", "PHE170379A", "PT_SIF1020", "PT_SIF1063", "PHE160315A", "PHE170398A", "PHE170380A", "PHE170365A", "UW148B", "UW473B", "UW492B", "UW248B", "TPA_HUN190023", "UW138B", "UW368B", "UW149B", "UW104B", "SMUTp_02", "SMUTp_01", "SMUTp_08", "PT_SIF0954", "PT_SIF1200", "TPA_BCC128", "TPA_BCC127", "TPA_AUSBR-45", "TPA_HUN180007", "PHE160246A", "UW327B", "CW87", "TPA_ESBCN002", "TPA_SWE-467", "TPA_EIR017", "TPA_HUN190017", "PHE160248A", "PHE130053A", "TPA_HUN180001", "TPA_SWE-662", "PHE130051A", "TPA_BCC138", "TPA_AUSBR-113", "TPA_SWE-1352", "PT_SIF0877_3", "PT_SIF1142", "TPA_EIR013", "AU15", "TPA_EIR008", "AU16", "TPA_BCC049", "CW84", "TPA_BCC052", "PHE170392A", "Seattle_81-4", "TPA_USL-SEA-83-2", "UW279B", "TPA_USL-SEA-86-1", "PHE170336B", "PHE150114A", "TPA_OMI021", "CW59", "CW82", "TPA_USL-Phil-3", "BAL3", "BAL73", "TPA_ZIM014", "TPA_ZIM018", "TPA_ZIM015", "PHE150166A", "PHE160306A", "PHE150168A", "TPA_BCC122", "PHE160294A", "TPA_HUN180004", "TPA_BCC136", "TPA_HUN190020", "PHE160287A", "TPA_BCC126", "TPA_BCC169", "TPA_BCC012", "PHE120029A", "PHE120033A", "TPA_USL-Haiti-B", "PHE160283A", "PHE130048A")



subsampled.ML.tips.6pCountry.pSublin.tree <- (ape::keep.tip(TPA.MLtree, subsampled.ML.tips.6pCountry.pSublin))

subsampled.ML.tips.6pCountry.pSublin.tree.data <- data.frame(fortify(subsampled.ML.tips.6pCountry.pSublin.tree),stringsAsFactors = F)
subsampled.ML.tips.6pCountry.pSublin.tree.data$Sample_Name <- subsampled.ML.tips.6pCountry.pSublin.tree.data$label 
subsampled.ML.tips.6pCountry.pSublin.tree.data <- plyr::join(subsampled.ML.tips.6pCountry.pSublin.tree.data, TPA.meta1.2.pinecone.havedates[,c("Sample_Name","TPA.pinecone.major","TPA.pinecone.sublineage", "Sample_Year")], by="Sample_Name", type="left")




plot.subsampled.ML.tips.6pCountry.pSublin.tree <- ggtree(subsampled.ML.tips.6pCountry.pSublin.tree) %<+% data.frame(Sample_Name=TPA.meta1.2.pinecone$Sample_Name, Sublineage=TPA.meta1.2.pinecone$TPA.pinecone.sublineage) + 
  geom_tippoint(aes(color=Sublineage), size=1, alpha=0.5) + 
  scale_color_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) 

plot.subsampled.ML.tips.6pCountry.pSublin.tree <- gheatmap(plot.subsampled.ML.tips.6pCountry.pSublin.tree,
               data.frame(row.names=TPA.meta1.2.pinecone$Sample_Name, Sublineage=TPA.meta1.2.pinecone$TPA.pinecone.sublineage), color=NULL,width=0.04, colnames_angle=0,colnames_offset_y=-1, font.size=2.5) + 
  scale_fill_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) +
  theme.text.size + theme(legend.key.size = unit(0.5,"line"))
Scale for 'fill' is already present. Adding another scale for 'fill', which will replace the existing scale.

plot subsampled ML subtree

plot.subsampled.ML.tips.6pCountry.pSublin.tree

Define function to extract and plot root-2-tip data from a tree or subtree

# Inputs
# - A maximum likelihood tree in phylo
# - a dataframe with the headers c("Sample_Name","Sample_Year")

plotRootToTip <- function(input.ml.tree, input.dates.df){
  tree.data <- data.frame(ggtree::fortify(input.ml.tree),stringsAsFactors = F)
  tree.data$Sample_Name <- tree.data$label
  tree.data <- plyr::join(tree.data, input.dates.df, by="Sample_Name", type="left")
  RootTotipDistances <- tree.data[tree.data$isTip==TRUE,"x"]
  treeLabels <- tree.data[tree.data$isTip==TRUE,"Sample_Name"]
  ntips <- length(treeLabels)
  treeDates <- as.numeric(tree.data[tree.data$isTip==TRUE,"Sample_Year"])
  maxdate <- max(treeDates)
  mindate <- min(treeDates)
  treeModel <- lm(RootTotipDistances ~ treeDates)
  treeCorrelation <- cor.test(treeDates, RootTotipDistances, method = "pearson", conf.level = 0.95)
  modelSummary <- summary(treeModel)
  xIntercept <- -coef(treeModel)[1]/coef(treeModel)[2]
  RootTotipDF <- data.frame(RootTotipDistances,treeDates)
  
  plot.tree.data.root2tip <- ggplot(data = RootTotipDF, aes(treeDates,  RootTotipDistances)) +
    geom_point(alpha=0.25,size=2, colour = "red") +
    theme_classic() +
    labs(x="Year",y="Root to tip distance") +
    #geom_smooth(method='lm',fullrange=T,se=T) +
    stat_smooth(method='lm',fullrange=T,se=T) +  
    ggtitle(paste0("Slope: ",formatC(modelSummary$coefficients[2], format = "e", digits = 3),"; ",
                  "TMRCA: ",round(xIntercept,1),
                  "\n", "Correlation Coefficient: ",round(treeCorrelation$estimate,3),
                  "; ", "R^2: ", format(modelSummary$r.squared,digits=3),"\n",ntips," tips","; Timespan: ",mindate,"-",maxdate)) +
    theme(plot.title = element_text(size = 9))
  
  return(plot.tree.data.root2tip)
}

now plot

p.subsampled.ML.tips.6pCountry.pSublin.root2tip <- plotRootToTip(subsampled.ML.tips.6pCountry.pSublin.tree, TPA.meta1.2.pinecone.havedates[,c("Sample_Name","Sample_Year")])

p.subsampled.ML.tips.6pCountry.pSublin.root2tip.2versions <- plot_grid(p.subsampled.ML.tips.6pCountry.pSublin.root2tip, p.subsampled.ML.tips.6pCountry.pSublin.root2tip + scale_x_continuous(limits = c(1400,2020)) + coord_cartesian(xlim=c(1400,2020), ylim=c(0,8.5e-5)), ncol=2, labels=c('B','C'), label_size=11) 
`geom_smooth()` using formula 'y ~ x'
`geom_smooth()` using formula 'y ~ x'
p.subsampled.ML.tips.6pCountry.pSublin.root2tip.2versions 

Plot ML Subtree with root-2-tip graph


#Cairo::Cairo(file=paste0(Figure_output_directory, "Supplementary_Figure15__ML-subtree1-with-root2tip_02-2021.svg"), width = 800, height = 800,type="svg",units = "pt")
plot_grid(plot.subsampled.ML.tips.6pCountry.pSublin.tree +ylim(-1,139), p.subsampled.ML.tips.6pCountry.pSublin.root2tip.2versions, ncol=1, scale=0.9, labels=c('A',''), label_size=11)

#dev.off()

Took sequence alignment from this tree, and analysed using BEAST 1.8.4

BEAST analysis (HYK subst model), comparing

Strict - Constant pop Strict - Skyline pop (10 cats) RelLogNormal - Constant pop RelLogNormal - Exponential pop RelLogNormal - Skyline pop (10 cats)

  • Can’t reject strict clock (ucldev.sd overlaps zero subtantially)
  • Stepping stone analysis shows Strick-Skyline is best model (although Strict Constant is nearly as close)

Bring in Strict Skyline BEAST tree and plot

# Bring in beast tree and extract tree data into dataframe
TPA.beast.tree <- read.beast(TPA.beast.subtree.file)
TPA.beast.tree.data <- data.frame(fortify(TPA.beast.tree),stringsAsFactors = F)


# BEAST tipnames have date included - lets remove that for plotting with metadata
TPA.beast.tipnames <- data.frame(beast.name=TPA.beast.tree@phylo$tip.label,stringsAsFactors = F)
TPA.beast.tipnames$meta.name <- gsub("\\|.+$","", TPA.beast.tipnames$beast.name)
TPA.beast.tree@phylo$tip.label <- TPA.beast.tipnames$meta.name
#TPA.beast.tree@phylo$tip.label


# Build plot
TPA.beast.plot1 <- ggtree(TPA.beast.tree,mrsd="2019-06-01",ladderize = T) + 
  theme_tree2() +
  # Add date lines for easy interpretation  
  scale_x_continuous(breaks=c(1300,1400,1500,1600,1700,1800,1850,1900,1925,1950,1975,2000,2020), minor_breaks=seq(1950, 2020, 5)) +
  theme(panel.grid.major   = element_line(color="grey50", size=.2),
        panel.grid.minor   = element_line(color="grey85", size=.2),
        panel.grid.major.y = element_blank(),
        panel.grid.minor.y = element_blank()) 
# Add posterior support as node points
TPA.beast.plot1 <- TPA.beast.plot1 + geom_point2(aes(subset=(!isTip & as.numeric(posterior)>0.8)),color="gray60",size=2.5,alpha=0.5, shape=18) + 
  geom_point2(aes(subset=(!isTip & as.numeric(posterior)>0.91)),color="gray40",size=2.5,shape=18,alpha=0.5) + 
  geom_point2(aes(subset=(!isTip & as.numeric(posterior)>=0.96)),color="black",size=2.5,shape=18,alpha=0.5)


# Plot 95% HPD intervals - geom_range seems unable to do correctly with this tree (known bug for tip dated trees), so extract data and plot using geom_segment
minmax <- t(matrix(unlist(TPA.beast.tree.data[!is.na(TPA.beast.tree.data$height_0.95_HPD),"height_0.95_HPD"]),nrow=2))
bar_df <- data.frame(node_id=TPA.beast.tree.data[!is.na(TPA.beast.tree.data$height_0.95_HPD),"node"],as.data.frame(minmax))
names(bar_df) <- c('node_id','min','max') 
bar_df <- bar_df %>% filter(node_id > Ntip(TPA.beast.tree@phylo))
bar_df <- bar_df %>% left_join(TPA.beast.plot1$data, by=c('node_id'='node')) %>% select(node_id,min,max,y)
mrcd.decimal <- decimal_date(as.Date("2019-06-01","%Y-%m-%d"))
TPA.beast.plot1 <- TPA.beast.plot1 + geom_segment(aes(x=mrcd.decimal-max, y=y, xend=mrcd.decimal-min, yend=y), data=bar_df, color='red', alpha=0.2, size=2.25)

TPA.beast.plot1 <- TPA.beast.plot1 + new_scale_fill()

TPA.beast.plot1 + geom_tiplab(size=2, align=T)

with metadata


TPA.beast.plot1.meta <- gheatmap(TPA.beast.plot1,
               data.frame(row.names=TPA.meta1.2.pinecone$Sample_Name, Sublineage=TPA.meta1.2.pinecone$TPA.pinecone.sublineage), color=NULL,width=0.05, offset=2,colnames_angle=0,colnames_offset_y=-1, font.size=2.5) + 
  scale_fill_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) +
  theme.text.size
TPA.beast.plot1.meta <- TPA.beast.plot1.meta + new_scale_fill()


TPA.beast.plot1.meta <- gheatmap(TPA.beast.plot1.meta,TPA.rawseq.countries.p, color=NULL,width=0.05,offset=36, colnames_angle=0,colnames_offset_y=-1, font.size=2.5) + 
  scale_fill_manual(name="Country",values=continental.country.cols.brew2$country.col, breaks=continental.country.cols.brew2$Geo_Country) +
  theme.text.size
TPA.beast.plot1.meta <- TPA.beast.plot1.meta + new_scale_fill()
beast.country.legend <- get_legend(TPA.beast.plot1.meta + theme(legend.key.size = unit(0.65,"line"),legend.position='right'))

TPA.beast.plot1.meta <- gheatmap(TPA.beast.plot1.meta,data.frame(row.names=TPA.meta1.2.pinecone$Sample_Name, Year=TPA.meta1.2.pinecone$Sample_5year.window, stringsAsFactors = F), color=NULL,width=0.05, offset=70,colnames_angle=0,colnames_offset_y=-1, font.size=2.5) + scale_fill_manual(name="Year",values=TPA.5year.window.brewcols$window.5year.cols[1:(length(TPA.5year.window.brewcols$window.5year.cols)-1)], breaks=TPA.5year.window.brewcols$window.5year[1:(length(TPA.5year.window.brewcols$window.5year)-1)]) +
  theme.text.size + 
  #theme(legend.key.size = unit(0.65,"line"),legend.position='left') #+
  #guides(fill=guide_legend(ncol=3)) +
  NULL
TPA.beast.plot1.meta <- TPA.beast.plot1.meta + new_scale_fill()
beast.year.legend <- get_legend(TPA.beast.plot1.meta + theme(legend.key.size = unit(0.65,"line"),legend.position='right'))


TPA.beast.plot1.meta <- TPA.beast.plot1.meta + geom_vline(xintercept = 2000, color='blue', alpha=0.5)
TPA.beast.plot1.meta <- TPA.beast.plot1.meta + annotate("rect",xmin=2000,xmax=2020,ymin=-1,ymax=138,alpha=0.1, fill='blue')

Look at and plot skyline data

beast.subtree.skyline <- read.table(beast.subtree.skyline.file, sep="\t", check.names=F, comment.char="", header=T, stringsAsFactors=F)

p.beast.subtree.skyline <- ggplot(beast.subtree.skyline, aes(Time,Median)) + 
  geom_line() +
  geom_ribbon(aes(ymin=Lower, ymax=Upper), alpha=0.2, fill='black') +
  theme_light() + 
  scale_x_continuous(breaks=c(seq(1740,2020,20)), expand=c(0.01,0.01)) +
  scale_y_log10() + 
  coord_cartesian(x=c(1750,2020), y=c(50,3000)) + 
  theme.text.size +
  #labs(y="Median effective population size", x="Year") + 
  labs(y="Relative genetic diversity", x="Year") + 
  geom_vline(xintercept = 2000, color='blue', alpha=0.5) +
  annotate("rect",xmin=2000,xmax=2020,ymin=0,ymax=10000,alpha=0.1, fill='blue')
#p.beast.subtree.skyline

Look at lineage preditions

beast.subtree.skyline.lineages <- read.table(beast.subtree.skyline.lineage.file, sep="\t", check.names=F, comment.char="", header=T, stringsAsFactors=F)

p.beast.subtree.skyline.lineages <- ggplot(beast.subtree.skyline.lineages, aes(Time,Median)) + 
  geom_line() +
  geom_ribbon(aes(ymin=Lower, ymax=Upper), alpha=0.2, fill='black') +
  theme_light() + 
  scale_x_continuous(breaks=c(seq(1740,2020,20)), expand=c(0.01,0.01)) +
  scale_y_log10() + 
  coord_cartesian(x=c(1750,2020), y=c(1,300)) + 
  theme.text.size +
  labs(y="Lineages", x="Year") + 
  geom_vline(xintercept = 2000, color='blue', alpha=0.5) +
  annotate("rect",xmin=2000,xmax=2020,ymin=0,ymax=500,alpha=0.1, fill='blue')
#p.beast.subtree.skyline.lineages

Make combined plot

skyline.row <- plot_grid(NULL,p.beast.subtree.skyline,NULL, ncol=3, rel_widths = c(1,3,1))
lineage.row <- plot_grid(NULL,p.beast.subtree.skyline.lineages,NULL, ncol=3, rel_widths = c(1,3,1))

#both.skyline.lineage.rows <- plot_grid(skyline.row, lineage.row, align=T, ncol=1, labels=c('B','C'))
both.skyline.lineage.rows <- plot_grid(skyline.row, align=T, ncol=1, labels=c('B'),label_size=11)


#plot.beast.with.skyline <- plot_grid(TPA.beast.plot1.meta + theme(legend.position='none') + ylim(-1,138), both.skyline.lineage.rows, ncol=1, align=T, rel_heights = c(2,2),labels=c('A',''), label_size=11)

plot.beast.with.skyline <- plot_grid(TPA.beast.plot1.meta + theme(legend.position='none') + ylim(-1,138), both.skyline.lineage.rows, ncol=1, align=T, rel_heights = c(3,1),labels=c('A',''), label_size=11)

beast.legend.combined <- plot_grid(beast.year.legend, NULL, ncol=1, rel_heights=c(3,1))



#Cairo::Cairo(file=paste0(Figure_output_directory, "Supplementary_Figure16_subsample138_BEAST-StrictCSkyline_02-2021.svg"), width = 800, height = 800,type="svg",units = "pt")
plot_grid(beast.legend.combined, plot.beast.with.skyline, ncol=2, rel_widths=c(1,10), labels=c('Key',''), label_size=11)

#dev.off()

Pull out MRCA nodes and date ranges from beast subtree and sublineages

# Subset metadata
TPA.meta1.2.beast.subset1 <- TPA.meta1.2.pinecone[TPA.meta1.2.pinecone$Sample_Name %in% as.phylo(TPA.beast.tree)$tip.label,]
# Define key sublineages
#Expanded.sublineages <- data.frame(Sublineage=c(2,3,5,6,12,19), stringsAsFactors = F)
Expanded.sublineages <- data.frame(Sublineage=c(1,2,8,14), stringsAsFactors = F)


# Run loop to extract MRCA node for each sublineage
Expanded.sublineage.nodes <- NULL
for (current.sublineage.exp1 in Expanded.sublineages$Sublineage) {
  Expanded.sublineage.nodes <- c(Expanded.sublineage.nodes, ape::getMRCA(as.phylo(TPA.beast.tree),as.character(TPA.meta1.2.beast.subset1[TPA.meta1.2.beast.subset1$TPA.pinecone.sublineage==current.sublineage.exp1,"Sample_Name"])))
}
Expanded.sublineages$node <- Expanded.sublineage.nodes
#Expanded.sublineages

# Split sublineage 2 in this tree creates a problem. Change it to 180
#Expanded.sublineages[Expanded.sublineages$sublineage==2,]
Expanded.sublineages[Expanded.sublineages$Sublineage==2,"node"] <- 180


TPA.beast.plot1 + geom_text2(aes(subset=!isTip, label=node), hjust=-.3, size=2) +
  geom_point2(aes(subset=(node %in% Expanded.sublineages$node)),color="red") +
  ggtitle("Red nodes indicate MRCA for each sublineage")

#Extract relevant nodes data from beast tree data
Expanded.sublineage.nodes.beast <- plyr::join(Expanded.sublineages,TPA.beast.tree.data[,c("node","height","height_0.95_HPD","height_median","height_range")], by="node")

# Data is in the form of "height" information - need to convert to years relative to mrcd (2019/06/01)
Expanded.sublineage.nodes.beast$mrca.median <- 2019.5 - Expanded.sublineage.nodes.beast$height_median
Expanded.sublineage.nodes.beast$year <- as.numeric(round(2019.5 - Expanded.sublineage.nodes.beast$height_median,0))


Expanded.sublineage.nodes.beast$mrca.95high <- round(2019.5 - sapply(1:nrow(Expanded.sublineage.nodes.beast),function(x) as.numeric(unlist(Expanded.sublineage.nodes.beast[x,"height_0.95_HPD"]))[1]))

Expanded.sublineage.nodes.beast$mrca.95low <- round(2019.5 - sapply(1:nrow(Expanded.sublineage.nodes.beast),function(x) as.numeric(unlist(Expanded.sublineage.nodes.beast[x,"height_0.95_HPD"]))[2]))


Expanded.sublineage.nodes.beast <- Expanded.sublineage.nodes.beast[order(Expanded.sublineage.nodes.beast$Sublineage),]
Expanded.sublineage.nodes.beast$Sublineage <- factor(Expanded.sublineage.nodes.beast$Sublineage, levels=rev(sublineages.cols.brew$sublineage))
Expanded.sublineage.nodes.beast$sub.order <- rev(c(1:nrow(Expanded.sublineage.nodes.beast)))

Repeat BEAST subsampling, but ensure all year are represented (and make a slightly bigger tree)


year.list <- sort(unique(TPA.meta1.2.pinecone.havedates$Sample_Year))


mysamplesize.2 <- 3
total.bootstraps.2 <- 1

all.bootstraps.lists.2 <- NULL
all.bootstraps.trees.2 <- c(rtree(20)) # create with random start tree to force into a multiphylo object
current.bootstrap.2 <- 0
repeat {
  country.sample.2 <- NULL
  for (current.year.2 in year.list) { 
    for (current.lineage.2 in sublineage.lineage.list2){
      for (current.country.2 in Country.list2){
        current.list.2 <- TPA.meta1.2.pinecone.havedates[(TPA.meta1.2.pinecone.havedates$TPA.pinecone.sublineage==current.lineage.2 & TPA.meta1.2.pinecone.havedates$Geo_Country==current.country.2 & TPA.meta1.2.pinecone.havedates$Sample_Year==current.year.2),"Sample_Name"]
        current.list.2 <- current.list.2[!is.na(current.list.2)]
        if (length(current.list.2)>1){
          current.sample.2 <- unique(sample(current.list.2,size=mysamplesize.2, replace=T))
          country.sample.2 <- c(as.vector(current.sample.2), country.sample.2)
        }
      }
    }
  }
  country.sample.2 <- c(country.sample.2, as.vector(TPA.meta1.2.pinecone.havedates[(TPA.meta1.2.pinecone.havedates$TPA.pinecone.sublineage=="Singleton"),"Sample_Name"]))
  
  current.bootstrap.2 <- current.bootstrap.2 + 1
  current.sample.tree.2 <- (ape::keep.tip(TPA.MLtree, country.sample.2))
  all.bootstraps.trees.2 <- c(all.bootstraps.trees.2,c(current.sample.tree.2),recursive=T)
  all.bootstraps.lists.2 <- c(all.bootstraps.lists.2, list(country.sample.2))
  if (current.bootstrap.2 == total.bootstraps.2){
    break
  }
}
all.bootstraps.trees.2 <- all.bootstraps.trees.2[c(2:(total.bootstraps.2+1))] # remove random start tree

#all.bootstraps.trees[[1]]
#subsampled.ML.tips.3pv.country.dates.sublin <- all.bootstraps.trees.2[[1]]$tip.label

# Outputs from a previous random loop used below to ensure sample remains the same
subsampled.ML.tips.3pv.country.dates.sublin <- c("Mexico_A-mcf", "TPA_RUS_Tuva-62", "TPA_RUS_Tuva-39", "TPA_RUS_Tuva-61", "PHE140073A", "UW337B", "UW186B", "UW330B", "UW213B", "UW215B", "PHE150129A", "TPA_UKBRG017", "TPA_BCC161", "TPA_OMI006", "UW231B", "UW187B", "K3", "SHE_V", "SHG_I2", "C3", "TPA_BCC165", "TPA_USL-BAL-2", "SS14_v2", "TPA_HUN200024", "TPA_HUN190022", "TPA_USL-SEA-81-8", "TPA_ZIM025", "TPA_ZIM019", "TPA_ZIM007", "UW262B", "UW391B", "PHE150151A", "TPA_UKBIR026", "TPA_OMI002", "TPA_BCC139", "TPA_BCC137", "TPA_UKBRG015", "PHE130041A", "PHE130050A", "UW376B", "PHE150159A", "UW280B", "UW244B", "TPA_BCC125", "PHE160254A", "PT_SIF1183", "PHE160249A", "PHE170379A", "PHE160315A", "PHE160260A", "PHE150131A", "PHE170402A", "PHE170380A", "UW473B", "UW492B", "TPA_USL-Phil-1", "PHE120030A", "PHE120014A", "PHE130043A", "PT_SIF1167", "PHE140093A", "TPA_HUN190023", "TPA_BCC058", "TPA_USL-SEA-87-1", "TPA_UKBIR050", "UW155B", "UW211B", "TPA_BCC038", "TPA_BCC034", "TPA_BCC008", "TPA_BCC009", "UW257B", "UW138B", "UW102B", "UW344B", "UW126B", "SMUTp_01", "SMUTp_08", "UW383B", "TPA_ALC115", "UW823B", "PHE170385A", "UW304B", "PT_SIF0954", "PT_SIF1200", "TPA_BCC128", "PHE130056A", "TPA_ALC036", "TPA_BCC032", "TPA_BCC132", "TPA_AUSBR-45", "TPA_BCC153", "TPA_AUSBR-39", "TPA_HUN180007", "UW411B", "TPA_ESBCN002", "PHE140074A", "TPA_SWE-467", "PHE150126A", "PHE170412A", "PHE150173A", "TPA_UKBRG009", "TPA_ESBCN004", "TPA_BCC123", "TPA_BCC147", "TPA_BCC063", "PHE120024A", "TPA_BCC174", "TPA_SWE-575", "TPA_HUN190017", "PHE160248A", "TPA_BCC176", "TPA_HUN180001", "PHE130054A", "UW852B", "PHE140081A", "UW259B", "TPA_AUSBR-113", "PHE160301A", "TPA_BCC102", "PT_SIF1278", "PT_SIF0877_3", "PHE160265A", "AU15", "TPA_EIR008", "TPA_ALC055", "TPA_BCC175", "PT_SIF1280", "TPA_BCC185", "TPA_BCC111", "TPA_BCC157", "TPA_BCC030", "PHE170409A", "TPA_BCC049", "TPA_BCC061", "TPA_BCC052", "PHE150161A", "TPA_ALC126", "TPA_OMI022", "UW189B", "UW279B", "TPA_OMI021", "PHE170401A", "CW59", "CW82", "BAL73", "TPA_ZIM015", "TPA_ZIM020", "PHE150118A", "PHE170333A", "PHE160302A", "PHE140089A", "PHE170381A", "PHE160263A", "TPA_BCC089", "PHE160316A", "TPA_BCC122", "PHE170386A", "PHE140076A", "PHE150149A", "TPA_BCC136", "PHE150170A", "TPA_UKBRG007", "TPA_BCC081", "TPA_BCC012", "PHE120029A", "PHE120033A", "TPA_USL-Haiti-B")



subsampled.ML.tips.3pv.country.dates.sublin.tree <- (ape::keep.tip(TPA.MLtree, subsampled.ML.tips.3pv.country.dates.sublin))

subsampled.ML.tips.3pv.country.dates.sublin.tree.data <- data.frame(fortify(subsampled.ML.tips.3pv.country.dates.sublin.tree),stringsAsFactors = F)
subsampled.ML.tips.3pv.country.dates.sublin.tree.data$Sample_Name <- subsampled.ML.tips.3pv.country.dates.sublin.tree.data$label 
subsampled.ML.tips.3pv.country.dates.sublin.tree.data <- plyr::join(subsampled.ML.tips.3pv.country.dates.sublin.tree.data, TPA.meta1.2.pinecone.havedates[,c("Sample_Name","TPA.pinecone.major","TPA.pinecone.sublineage", "Sample_Year")], by="Sample_Name", type="left")

subsampled.metalist2 <- TPA.meta1.2.pinecone[(TPA.meta1.2.pinecone$Sample_Name %in% subsampled.ML.tips.3pv.country.dates.sublin),c("Sample_Name","Cleaned_fastq_id","Sample_Year")] 


plot.subsampled.ML.tips.3pv.country.dates.sublin.tree <- ggtree(subsampled.ML.tips.3pv.country.dates.sublin.tree) %<+% data.frame(Sample_Name=TPA.meta1.2.pinecone$Sample_Name, Sublineage=TPA.meta1.2.pinecone$TPA.pinecone.sublineage) + 
  geom_tippoint(aes(color=Sublineage), size=1, alpha=0.5) + 
  scale_color_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) 

plot.subsampled.ML.tips.3pv.country.dates.sublin.tree <- gheatmap(plot.subsampled.ML.tips.3pv.country.dates.sublin.tree,
               data.frame(row.names=TPA.meta1.2.pinecone$Sample_Name, Sublineage=TPA.meta1.2.pinecone$TPA.pinecone.sublineage), color=NULL,width=0.04, colnames_angle=0,colnames_offset_y=-1, font.size=2.5) + 
  scale_fill_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) +
  theme.text.size + theme(legend.key.size = unit(0.5,"line"))
Scale for 'fill' is already present. Adding another scale for 'fill', which will replace the existing scale.
plot.subsampled.ML.tips.3pv.country.dates.sublin.tree

do root2tip for second subsampled tree

p.subsampled.ML.tips.3pv.country.dates.sublin.root2tip <- plotRootToTip(subsampled.ML.tips.3pv.country.dates.sublin.tree, TPA.meta1.2.pinecone.havedates[,c("Sample_Name","Sample_Year")])


plot_grid(p.subsampled.ML.tips.3pv.country.dates.sublin.root2tip, p.subsampled.ML.tips.3pv.country.dates.sublin.root2tip + scale_x_continuous(limits = c(1400,2020)) + coord_cartesian(xlim=c(1400,2020), ylim=c(0,8.5e-5)), ncol=2)
`geom_smooth()` using formula 'y ~ x'
`geom_smooth()` using formula 'y ~ x'

Plot repeat subsetted tree and skyline info

repeat.subsampled.skyline.tree <- read.beast(repeat.subsampled.skyline.tree.file)
repeat.subsampled.skyline.tree.data <- data.frame(fortify(repeat.subsampled.skyline.tree),stringsAsFactors = F)

# BEAST tipnames have date included - lets remove that for plotting with metadata
repeat.subsampled.skyline.tree.tipnames <- data.frame(beast.name=repeat.subsampled.skyline.tree@phylo$tip.label,stringsAsFactors = F)
repeat.subsampled.skyline.tree.tipnames$meta.name <- gsub("\\|.+$","", repeat.subsampled.skyline.tree.tipnames$beast.name)
repeat.subsampled.skyline.tree@phylo$tip.label <- repeat.subsampled.skyline.tree.tipnames$meta.name

# Build plot
repeat.subsampled.skyline.plot1 <- ggtree(repeat.subsampled.skyline.tree,mrsd="2019-06-01",ladderize = T) + 
  theme_tree2() +
  # Add date lines for easy interpretation  
  scale_x_continuous(breaks=c(1300,1400,1500,1600,1700,1800,1850,1900,1925,1950,1975,2000,2020), minor_breaks=seq(1950, 2020, 5)) +
  theme(panel.grid.major   = element_line(color="grey50", size=.2),
        panel.grid.minor   = element_line(color="grey85", size=.2),
        panel.grid.major.y = element_blank(),
        panel.grid.minor.y = element_blank()) 
# Add posterior support as node points
repeat.subsampled.skyline.plot1 <- repeat.subsampled.skyline.plot1 + geom_point2(aes(subset=(!isTip & as.numeric(posterior)>0.8)),color="gray60",size=2.5,alpha=0.5, shape=18) + 
  geom_point2(aes(subset=(!isTip & as.numeric(posterior)>0.91)),color="gray40",size=2.5,shape=18,alpha=0.5) + 
  geom_point2(aes(subset=(!isTip & as.numeric(posterior)>=0.96)),color="black",size=2.5,shape=18,alpha=0.5)

# Plot 95% HPD intervals - geom_range seems unable to do correctly with this tree (known bug for tip dated trees), so extract data and plot using geom_segment
rep.minmax <- t(matrix(unlist(repeat.subsampled.skyline.tree.data[!is.na(repeat.subsampled.skyline.tree.data$height_0.95_HPD),"height_0.95_HPD"]),nrow=2))
rep.bar_df <- data.frame(node_id=repeat.subsampled.skyline.tree.data[!is.na(repeat.subsampled.skyline.tree.data$height_0.95_HPD),"node"],as.data.frame(rep.minmax))
names(rep.bar_df) <- c('node_id','min','max') 
rep.bar_df <- rep.bar_df %>% filter(node_id > Ntip(repeat.subsampled.skyline.tree@phylo))
rep.bar_df <- rep.bar_df %>% left_join(repeat.subsampled.skyline.plot1$data, by=c('node_id'='node')) %>% select(node_id,min,max,y)
rep.mrcd.decimal <- decimal_date(as.Date("2019-06-01","%Y-%m-%d"))
repeat.subsampled.skyline.plot1 <- repeat.subsampled.skyline.plot1 + geom_segment(aes(x=rep.mrcd.decimal-max, y=y, xend=rep.mrcd.decimal-min, yend=y), data=rep.bar_df, color='red', alpha=0.2, size=2.25)
repeat.subsampled.skyline.plot1 <- repeat.subsampled.skyline.plot1 + new_scale_fill()

# Add markers after 2000
repeat.subsampled.skyline.plot1 <- repeat.subsampled.skyline.plot1 + geom_vline(xintercept = 2000, color='blue', alpha=0.5) + 
  annotate("rect",xmin=2000,xmax=2020,ymin=-1,ymax=170,alpha=0.1, fill='blue')

repeat.subsampled.skyline.plot1 + geom_tiplab(size=1.5, align=T)

NA
NA
NA
# Skyline
rep.beast.subtree.skyline <- read.table(repeat.subsampled.skyline.data.file, sep="\t", check.names=F, comment.char="", header=T, stringsAsFactors=F)
p.rep.beast.subtree.skyline <- ggplot(rep.beast.subtree.skyline, aes(Time,Median)) + 
  geom_line() + geom_ribbon(aes(ymin=Lower, ymax=Upper), alpha=0.2, fill='black') +
  theme_light() + 
  scale_x_continuous(breaks=c(seq(1740,2020,20)), expand=c(0.01,0.01)) + scale_y_log10() + 
  coord_cartesian(x=c(1750,2020), y=c(50,3000)) + 
  theme.text.size + labs(y="Relative genetic diversity", x="Year") + 
  geom_vline(xintercept = 2000, color='blue', alpha=0.5) + annotate("rect",xmin=2000,xmax=2020,ymin=0,ymax=10000,alpha=0.1, fill='blue')

# Lineages
rep.beast.subtree.skyline.lineages <- read.table(repeat.subsampled.skyline.lineages.data.file, sep="\t", check.names=F, comment.char="", header=T, stringsAsFactors=F)
p.rep.beast.subtree.skyline.lineages <- ggplot(rep.beast.subtree.skyline.lineages, aes(Time,Median)) + 
  geom_line() + geom_ribbon(aes(ymin=Lower, ymax=Upper), alpha=0.2, fill='black') +
  theme_light() + 
  scale_x_continuous(breaks=c(seq(1740,2020,20)), expand=c(0.01,0.01)) + scale_y_log10() + 
  coord_cartesian(x=c(1750,2020), y=c(1,300)) + 
  theme.text.size + labs(y="Lineages", x="Year") + 
  geom_vline(xintercept = 2000, color='blue', alpha=0.5) + annotate("rect",xmin=2000,xmax=2020,ymin=0,ymax=500,alpha=0.1, fill='blue')
#p.rep.beast.subtree.skyline.lineages



# Make combined plot
rep.skyline.row <- plot_grid(NULL,p.rep.beast.subtree.skyline,NULL, ncol=3, rel_widths = c(1,3,1))
rep.lineage.row <- plot_grid(NULL,p.rep.beast.subtree.skyline.lineages,NULL, ncol=3, rel_widths = c(1,3,1))
#rep.both.skyline.lineage.rows <- plot_grid(rep.skyline.row, rep.lineage.row, align=T, ncol=1, labels=c('B','C'))
rep.both.skyline.lineage.rows <- plot_grid(rep.skyline.row, align=T, ncol=1, labels=c('B'),label_size=11)

#plot.beast.with.skyline.repeat <- plot_grid(repeat.subsampled.skyline.plot1 + theme(legend.position='none'), rep.both.skyline.lineage.rows, ncol=1, align=T, rel_heights = c(2,2),labels=c('A',''), label_size=11)

plot.beast.with.skyline.repeat <- plot_grid(repeat.subsampled.skyline.plot1 + theme(legend.position='none'), rep.both.skyline.lineage.rows, ncol=1, align=T, rel_heights = c(3,1),labels=c('A',''), label_size=11)



#plot.beast.with.skyline <- plot_grid(TPA.beast.plot1.meta + theme(legend.position='none'), skyline.row, ncol=1, align=T, rel_heights = c(2,1),labels=c('A','B'), label_size=11)
#beast.legend.combined <- plot_grid(beast.year.legend, NULL, ncol=1, rel_heights=c(3,1))


#Cairo::Cairo(file=paste0(Figure_output_directory, "Supplementary_Figure17_subsample2-168_BEAST_StrictCSkyline_02-2021.svg"), width = 800, height = 800,type="svg",units = "pt")
plot.beast.with.skyline.repeat 

#dev.off()

Plotting Root-to-tip

# Define function
plot.subtree.R2T <- function(maintree, tips, dates.df){
  subtree.temp  <- ape::keep.tip(maintree, as.character(tips))
  plotRootToTip(subtree.temp, dates.df[,c("Sample_Name","Sample_Year")])
  plot_grid(ggtree(subtree.temp),plotRootToTip(subtree.temp, dates.df[,c("Sample_Name","Sample_Year")]),ncol=2)
}

Full tree dataset for BEAST1/2:

full.beast2.tree <- read.beast(full.beast2.tree.file)
tree.subsampled.ML.tips.full.data.for.beast2 <- (ape::keep.tip(TPA.MLtree, gsub("\\|.+$","",full.beast2.tree@phylo$tip.label, perl =T)))

tree.subsampled.ML.tips.full.data.for.beast2.r2t <- plot.subtree.R2T(tree.subsampled.ML.tips.full.data.for.beast2, gsub("\\|.+$","",full.beast2.tree@phylo$tip.label), TPA.meta1.2.pinecone.havedates[,c("Sample_Name","Sample_Year")])
`geom_smooth()` using formula 'y ~ x'
#Cairo::Cairo(file=paste0(Figure_output_directory, "Supplementary_Figure18__ML-tree.fulltree520-with-root2tip_02-2021.svg"), width = 800, height = 600,type="svg",units = "pt")
tree.subsampled.ML.tips.full.data.for.beast2.r2t

#dev.off()


Pull in data for full BEAST2 tree

Full Beast tree

full.beast2.tree <- read.beast(full.beast2.tree.file)
full.beast2.tree.data <- data.frame(fortify(full.beast2.tree),stringsAsFactors = F)


# Lets sort out the date of various events - relate everything in years
full.beast2.tree.data$mrca.median <- 2019.5 - full.beast2.tree.data$height_median
full.beast2.tree.data$year <- as.numeric(round(2019.5 - full.beast2.tree.data$height_median,0))

full.beast2.tree.data$mrca.95high <- round(2019.5 - sapply(1:nrow(full.beast2.tree.data),function(x) as.numeric(unlist(full.beast2.tree.data[x,"height_0.95_HPD"]))[1]))

full.beast2.tree.data$mrca.95low <- round(2019.5 - sapply(1:nrow(full.beast2.tree.data),function(x) as.numeric(unlist(full.beast2.tree.data[x,"height_0.95_HPD"]))[2]))


# Join metadata
full.beast2.tree.data$Sample_Name <- gsub("\\|.+$","", full.beast2.tree.data$label)
full.beast2.tree.data.meta <- plyr::join(full.beast2.tree.data, TPA.meta1.2.pinecone[,c("Sample_Name", "Geo_Country","TPA.pinecone.sublineage","Sample_Year")], by="Sample_Name", type="left")

full.beast2.tree.data.meta <- full.beast2.tree.data.meta[full.beast2.tree.data.meta$isTip==T,]

Extract some key dates


# Plot tree with node labels (to visualise and identify key nodes)
ggtree(full.beast2.tree) + geom_text2(aes(subset=!isTip, label=node), hjust=-.3, size=2.5, color="blue") 

# Split sublineage 1 in this tree creates a problem. Change it to 528 (MRCA of main clade)
Expanded.sublineages[Expanded.sublineages$Sublineage==1,"node"] <- 528



# Extract dates for the MRCAs - when did those sublineages first arise? Pretty old!
plyr::join(Expanded.sublineages, full.beast2.tree.data[,c("node","mrca.median","year","mrca.95high","mrca.95low")], by="node")



ggtree(full.beast2.tree,mrsd="2019-06-01",ladderize = T) + geom_text2(aes(subset=!isTip, label=node), hjust=-.3, size=2) +
  geom_point2(aes(subset=(node %in% Expanded.sublineages$node)),color="blue") +
  ggtitle("Red nodes indicate MRCA for each sublineage")

Lets plot the BEAST tree

# BEAST tipnames have date included - lets remove that for plotting with metadata
full.beast2.tipnames <- data.frame(beast.name=full.beast2.tree@phylo$tip.label,stringsAsFactors = F)
full.beast2.tipnames$meta.name <- gsub("\\|.+$","", full.beast2.tipnames$beast.name)
full.beast2.tree@phylo$tip.label <- full.beast2.tipnames$meta.name
#TPA.beast.tree@phylo$tip.label


# Build plot
full.beast2.tree.plot1 <- ggtree(full.beast2.tree,mrsd="2019-06-01",ladderize = T) + 
  theme_tree2() +
  # Add date lines for easy interpretation  
  scale_x_continuous(breaks=c(1300,1400,1500,1600,1700,1800,1850,1900,1925,1950,1975,2000,2020), minor_breaks=seq(1950, 2020, 5)) +
  theme(panel.grid.major   = element_line(color="grey50", size=.2),
        panel.grid.minor   = element_line(color="grey85", size=.2),
        panel.grid.major.y = element_blank(),
        panel.grid.minor.y = element_blank()) 
# Add posterior support as node points
full.beast2.tree.plot1 <- full.beast2.tree.plot1 + geom_point2(aes(subset=(!isTip & as.numeric(posterior)>0.8)),color="gray60",size=2.5,alpha=0.5, shape=18) + 
  geom_point2(aes(subset=(!isTip & as.numeric(posterior)>0.91)),color="gray40",size=2.75,shape=18,alpha=0.5) + 
  geom_point2(aes(subset=(!isTip & as.numeric(posterior)>=0.96)),color="black",size=2.75,shape=18,alpha=0.5) +
    geom_rootedge(rootedge=50)


# Plot 95% HPD intervals - geom_range seems unable to do correctly with this tree (known bug for tip dated trees), so extract data and plot using geom_segment
minmax.fulltree <- t(matrix(unlist(full.beast2.tree.data[!is.na(full.beast2.tree.data$height_0.95_HPD),"height_0.95_HPD"]),nrow=2))
bar_df.fulltree <- data.frame(node_id=full.beast2.tree.data[!is.na(full.beast2.tree.data$height_0.95_HPD),"node"],as.data.frame(minmax.fulltree))
names(bar_df.fulltree) <- c('node_id','min','max') 
bar_df.fulltree <- bar_df.fulltree %>% filter(node_id > Ntip(full.beast2.tree@phylo))
bar_df.fulltree <- bar_df.fulltree %>% left_join(full.beast2.tree.plot1$data, by=c('node_id'='node')) %>% select(node_id,min,max,y)
mrcd.decimal.fulltree <- decimal_date(as.Date("2019-06-01","%Y-%m-%d"))
full.beast2.tree.plot1 <- full.beast2.tree.plot1 + geom_segment(aes(x=mrcd.decimal.fulltree-max, y=y, xend=mrcd.decimal.fulltree-min, yend=y), data=bar_df.fulltree, color='red', alpha=0.2, size=1.5)

full.beast2.tree.plot1 <- full.beast2.tree.plot1 + new_scale_fill()
#full.beast2.tree.plot1 #+ geom_tiplab(size=2, align=T)

# Add Metadata
full.beast2.tree.plot1.meta <- gheatmap(full.beast2.tree.plot1,
               data.frame(row.names=TPA.meta1.2.pinecone$Sample_Name, Sublineage=TPA.meta1.2.pinecone$TPA.pinecone.sublineage), color=NULL,width=0.05, offset=2,colnames_angle=0,colnames_offset_y=-1.5, font.size=2.25,) + 
  scale_fill_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) +
  theme.text.size
full.beast2.tree.plot1.meta <- full.beast2.tree.plot1.meta + new_scale_fill()

full.beast2.tree.plot1.meta <- gheatmap(full.beast2.tree.plot1.meta,TPA.rawseq.countries.p, color=NULL,width=0.05,offset=36, colnames_angle=0,colnames_offset_y=-1.5, font.size=2.25) + 
  scale_fill_manual(name="Country",values=continental.country.cols.brew2$country.col, breaks=continental.country.cols.brew2$Geo_Country) +
  theme.text.size
full.beast2.tree.plot1.meta <- full.beast2.tree.plot1.meta + new_scale_fill()
#beast.country.legend <- get_legend(TPA.beast.plot1.meta + theme(legend.key.size = unit(0.65,"line"),legend.position='right'))

full.beast2.tree.plot1.meta <- gheatmap(full.beast2.tree.plot1.meta,data.frame(row.names=TPA.meta1.2.pinecone$Sample_Name, Year=TPA.meta1.2.pinecone$Sample_5year.window, stringsAsFactors = F), color=NULL,width=0.05, offset=70,colnames_angle=0,colnames_offset_y=-1.5, font.size=2.25) + scale_fill_manual(name="Year",values=TPA.5year.window.brewcols$window.5year.cols[1:(length(TPA.5year.window.brewcols$window.5year.cols)-1)], breaks=TPA.5year.window.brewcols$window.5year[1:(length(TPA.5year.window.brewcols$window.5year)-1)]) +
  theme.text.size + theme(legend.key.size = unit(0.55,"line"), legend.position="left") +
  coord_cartesian(y=c(-5,522)) +
  NULL
full.beast2.tree.plot1.meta <- full.beast2.tree.plot1.meta + new_scale_fill()
#full.beast2.tree.plot1.meta.legend <- get_legend(full.beast2.tree.plot1.meta + theme(legend.key.size = unit(0.65,"line"),legend.position='right'))


full.beast2.tree.plot1.meta <- full.beast2.tree.plot1.meta + geom_vline(xintercept = 2000, color='blue', alpha=0.5)
full.beast2.tree.plot1.meta <- full.beast2.tree.plot1.meta + annotate("rect",xmin=2000,xmax=2020,ymin=-4,ymax=521,alpha=0.1, fill='blue')


full.beast2.tree.plot1.meta #+ geom_text2(aes(subset=!isTip, label=node), hjust=-.3, size=2)

Pull in skyline analysis for full beast2 tree

sublineage.skylines.filepath <- beast2.runs.filepath

beast2.full.skyline <- read.table(paste0(beast2.runs.filepath,beast2.full.skyline.path), sep="\t", header=T)
beast2.full.lineages <- read.table(paste0(beast2.runs.filepath,beast2.full.lineages.path), sep="\t", header=T)

# Chris Ruis' script to extract distribution of trees supporting expansion above baseline
# In this analysis, looked for 2-fold expansion (-p 100), in which 0.6745 (67.5%) supported expansion
beast2.full.popdistro <- read.table(paste0(beast2.runs.filepath,beast2.full.popdistro.path), sep="\t", header=T)


# plot skyline
beast2.full.skyline.plot <- ggplot(beast2.full.skyline, aes(Time,Median)) + 
  geom_line() + geom_ribbon(aes(ymin=Lower, ymax=Upper), alpha=0.2, fill='black') +
  theme_light() + 
  scale_x_continuous(breaks=c(seq(1740,2020,20)), expand=c(0.01,0.01)) + 
  scale_y_log10() + 
  coord_cartesian(x=c(1740,2020),y=c(30,3000)) + 
  theme.text.size + labs(y="Relative genetic\ndiversity", x="Year") + 
  geom_vline(xintercept = 2000, color='blue', alpha=0.5) +
  theme(strip.background = element_rect(color='white', fill='white',linetype="solid"), strip.text.y=element_text(color = "grey25",angle=0, size=10))


# Plot 'lineages through time'
beast2.full.lineages.plot <- ggplot(beast2.full.lineages, aes(Time,Median)) + 
  geom_line() + geom_ribbon(aes(ymin=Lower, ymax=Upper), alpha=0.2, fill='black') +
  theme_light() + 
  scale_x_continuous(breaks=c(seq(1740,2020,20)), expand=c(0.01,0.01)) + 
  scale_y_log10() + 
  coord_cartesian(x=c(1740,2020),y=c(1,1000)) + 
  theme.text.size + labs(y="Inferred Lineages", x="Year") + 
  geom_vline(xintercept = 2000, color='blue', alpha=0.5) +
  theme(strip.background = element_rect(color='white', fill='white',linetype="solid"), strip.text.y=element_text(color = "grey25",angle=0, size=10))


# Plot population expansion date distro
beast2.full.popdistros.starts <- ggplot(beast2.full.popdistro[beast2.full.popdistro$Increase_date>0,], aes("Full Tree",Increase_date)) +
  geom_sina(alpha=0.75,color="grey80", size=1) + 
  geom_boxplot(alpha=0.0,outlier.shape = NA, width=0.25) +
  coord_cartesian(ylim=c(1740,2020)) +
  scale_y_continuous(breaks=c(seq(1740,2020,20)), expand=c(0.01,0.01), limits = c(1740,2020)) + 
  theme_light() + 
  coord_flip() + theme.text.size +
  theme(strip.background = element_rect(color='white', fill='white',linetype="solid"), strip.text.y=element_text(color = "grey25",angle=0, size=10)) +
  theme(axis.text.y=element_blank(), axis.ticks.y=element_blank()) +
  labs(y="Year", x="Distribution density\n(start of 2-fold\npopulation expansion)") + 
  geom_hline(yintercept = 2000, color='blue', alpha=0.5) +
  NULL
Coordinate system already present. Adding new coordinate system, which will replace the existing one.
# alternate plot type
beast2.full.popdistros.starts.densiplot <- ggplot(beast2.full.popdistro[beast2.full.popdistro$Increase_date>0,], aes(x=Increase_date)) + 
  geom_density() +
  coord_cartesian(xlim=c(1740,2020)) +
  #scale_x_continuous(breaks=c(seq(1740,2020,20)), expand=c(0.01,0.01), limits=c(1740,2020)) + 
  scale_x_continuous(breaks=c(seq(1740,2020,20)), expand=c(0.01,0.01)) + 
  theme_light() + 
  theme.text.size + 
  labs(x="Year", y="Distribution density\n(start of 2-fold\npopulation expansion)") + 
  geom_vline(xintercept = 2000, color='blue', alpha=0.5) +
  NULL
  



#plot_grid(beast2.full.skyline.plot,beast2.full.lineages.plot, ncol=1, align=T)
#plot_grid(beast2.full.skyline.plot + x.theme.strip, beast2.full.lineages.plot + x.theme.strip, beast2.full.popdistros.starts, ncol=1, align=T)

#plots.beast2.full.skyline.distro.combi <- plot_grid(beast2.full.skyline.plot + x.theme.strip, beast2.full.lineages.plot + x.theme.strip, beast2.full.popdistros.starts.densiplot, ncol=1, align='v',axis='t', labels = c('B','C','D'), label_size = 11,  label_x=0, label_y=1, scale=0.95)

plots.beast2.full.skyline.distro.combi <- plot_grid(beast2.full.skyline.plot + x.theme.strip, beast2.full.popdistros.starts.densiplot, ncol=1, align='v',axis='t', labels = c('B','C'), label_size = 11,  label_x=0, label_y=1, scale=0.95)


plots.beast2.full.skyline.distro.combi

Make combined plot (beast2 full + skylines)

#arrange.plots.beast2.full.skyline.distro.combi <- plot_grid('',plots.beast2.full.skyline.distro.combi, '', ncol=1, rel_heights=c(1,4,2))
arrange.plots.beast2.full.skyline.distro.combi <- plot_grid('',plots.beast2.full.skyline.distro.combi, '', ncol=1, rel_heights=c(1,4,4))


# Plot full BEAST tree with metadata strips
plot.full.beast2.with.skyline.distros <- plot_grid(full.beast2.tree.plot1.meta,arrange.plots.beast2.full.skyline.distro.combi,ncol=2, rel_widths=c(4,2), labels=c('A',''), label_size=11)

# Plot full BEAST tree without metadata
#plot.full.beast2.with.skyline.distros <- plot_grid(full.beast2.tree.plot1 + geom_vline(xintercept = 2000, color='blue', alpha=0.5) + annotate("rect",xmin=2000,xmax=2020,ymin=-4,ymax=521,alpha=0.1, fill='blue'), arrange.plots.beast2.full.skyline.distro.combi,ncol=2, rel_widths=c(4,2), labels=c('A',''), label_size=11)


#Cairo::Cairo(file=paste0(Figure_output_directory, "Figure3_Full-beast2+_skyline-+pop-expansion__02-2021.svg"), width = 1500, height = 1000,type="svg",units = "pt")
plot.full.beast2.with.skyline.distros

#dev.off()

Look at explicit support for population decline and expansion within the Beast2 tree distribution

Extract trees supporting a population 2-fold decline within a defined window (1990-2005) using Chris Ruis’ script:
python3 /nfs/users/nfs_m/mb29/scripts/population_change_support_BEAST.py -t TPA-uber_beast2_strict-skyline-500M_10pop_combined.trees -l TPA-uber_beast2_strict-skyline-500M_10pop_combined.log -p 50 -w 1990 2005 --decrease -d 2019.5 -b 2 -o beast2_strict-skyline-500M_10pop_pop-decline.1990-2005.p50

Analysis shows 82.8% of trees (11191/ ) support a population decline between 1990-2005.

Extract trees supporting a 2-fold population increase within a defined window (2000-2015) using Chris Ruis’ script:
python3 /nfs/users/nfs_m/mb29/scripts/population_change_support_BEAST.py -t TPA-uber_beast2_strict-skyline-500M_10pop_combined.trees -l TPA-uber_beast2_strict-skyline-500M_10pop_combined.log -p 100 -w 2000 2015 -d 2019.5 -b 2

Analysis shows 83.3% of trees (11245/ ) support a population increase between 2000-2015.

To be consistent with the ‘decline’ plot, extracted trees supporting a 2-fold population increase within a defined window (1990-2015) using Chris Ruis’ script:
python3 /nfs/users/nfs_m/mb29/scripts/population_change_support_BEAST.py -t TPA-uber_beast2_strict-skyline-500M_10pop_combined.trees -l TPA-uber_beast2_strict-skyline-500M_10pop_combined.log -p 100 -w 1990 2015 -d 2019.5 -b 2

Analysis shows 58.5% of trees (11245/ ) support a population increase between 1990-2015.


Plot distributions

beast2.pop.decline <- read.csv(beast2.pop.decline.file, header=T, stringsAsFactors=F)
beast2.pop.increase <- read.csv(beast2.pop.increase.file, header=T, stringsAsFactors=F)

beast2.pop.decline$query <- "Decline"
beast2.pop.increase$query <- "Expansion"
beast2.pop.decline.increase <- rbind(beast2.pop.decline,beast2.pop.increase)

# Create dataframe with supporting values for text plotting
#decline.support.value <- 82.8
#increase.support.value <- 83.3
decline.support.value <- "90.7"
increase.support.value <- "59.0"



beast.decline.increase.support.values <- data.frame(query=c("Decline","Expansion"),proportion=c(decline.support.value,increase.support.value), median.date=c(median(beast2.pop.decline$Date_of_change), median(beast2.pop.increase$Date_of_change)), stringsAsFactors=F)


p.beast2.full.popdecline.increase.densiplot <- ggplot(beast2.pop.decline.increase, aes(x=Date_of_change, group=query, color=query, fill=query)) + 
  geom_density(alpha=0.25) +
  scale_x_continuous(expand=c(0.01,0.01)) + 
  theme_light() + 
  theme.text.size + 
  labs(x="Year", y="Posterior distribution density\n(start of 2-fold population decline/expansion)", color="Key") + 
  guides(fill=FALSE) +
  geom_text(data=beast.decline.increase.support.values, aes(x=median.date, y=0.45, label=paste0(proportion,"% of supporting trees")),size=3) + 
  geom_text(data=beast.decline.increase.support.values, aes(x=median.date, y=0.5, label=paste0("median date: ",round(median.date,1))),size=3) + 
  theme(legend.position = 'top') 
  #geom_vline(data=beast.decline.increase.support.values, aes(xintercept=median.date, color=query)) +
  NULL
NULL
#Cairo::Cairo(file=paste0(Figure_output_directory, "Supplementary_Figure8__Skyline-pop-decline+expansion-dates__02-2021.svg"), width = 450, height = 300,type="svg",units = "pt")  
p.beast2.full.popdecline.increase.densiplot

#dev.off()

Look at trees supporting or not-supporting expansion

pop.decline.supporting.trees <- read.nexus(pop.decline.supporting.trees.file)
pop.decline.supporting.trees.sample25 <-sample(pop.decline.supporting.trees,size=25)

pop.decline.notsupporting.trees <- read.nexus(pop.decline.notsupporting.trees.file)
pop.decline.notsupporting.trees.sample25 <-sample(pop.decline.notsupporting.trees,size=25)

TPA.meta1.2.pinecone$Sample_Name.dates <- paste0(TPA.meta1.2.pinecone$Sample_Name,"|",TPA.meta1.2.pinecone$Sample_Year)


p.pop.decline.notsupporting.trees.sample25 <- ggdensitree(pop.decline.notsupporting.trees.sample25, alpha=0.1,mrsd="2019-06-01") + 
  theme_tree2()
Ignoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsd
p.pop.decline.notsupporting.trees.sample25 <- p.pop.decline.notsupporting.trees.sample25 %<+% data.frame(Sample_Name=TPA.meta1.2.pinecone$Sample_Name.dates, Sublineage=TPA.meta1.2.pinecone$TPA.pinecone.sublineage) + 
  geom_tippoint(aes(color=Sublineage), size=1, alpha=0.5) + 
  scale_color_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) +
  # Add date lines for easy interpretation  
  scale_x_continuous(breaks=c(1300,1400,1500,1600,1700,1800,1850,1900,1925,1950,1975,2000,2020), minor_breaks=seq(1950, 2020, 5)) +
  theme(panel.grid.major   = element_line(color="grey50", size=.2),
        panel.grid.minor   = element_line(color="grey85", size=.2),
        panel.grid.major.y = element_blank(),
        panel.grid.minor.y = element_blank()) + 
  ggtitle("Trees not supporting population expansion") +
  theme(plot.title = element_text(size = 9))
#p.pop.decline.notsupporting.trees.sample25


p.pop.decline.supporting.trees.sample25 <- ggdensitree(pop.decline.supporting.trees.sample25, alpha=0.1,mrsd="2019-06-01") + 
  theme_tree2()
Ignoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsdIgnoring unknown parameters: mrsd
p.pop.decline.supporting.trees.sample25 <- p.pop.decline.supporting.trees.sample25 %<+% data.frame(Sample_Name=TPA.meta1.2.pinecone$Sample_Name.dates, Sublineage=TPA.meta1.2.pinecone$TPA.pinecone.sublineage) + 
  geom_tippoint(aes(color=Sublineage), size=1, alpha=0.5) + 
  scale_color_manual(name="Sublineage",values=sublineages.cols.brew$sublineage.cols, breaks=sublineages.cols.brew$sublineage) +
  # Add date lines for easy interpretation  
  scale_x_continuous(breaks=c(1300,1400,1500,1600,1700,1800,1850,1900,1925,1950,1975,2000,2020), minor_breaks=seq(1950, 2020, 5)) +
  theme(panel.grid.major   = element_line(color="grey50", size=.2),
        panel.grid.minor   = element_line(color="grey85", size=.2),
        panel.grid.major.y = element_blank(),
        panel.grid.minor.y = element_blank()) +
  ggtitle("Trees supporting population expansion") +
  theme(plot.title = element_text(size = 9))
#p.pop.decline.supporting.trees.sample25



plot_grid(p.pop.decline.supporting.trees.sample25, p.pop.decline.notsupporting.trees.sample25, ncol=1)

There are no obvious differences in tree topology here. It is likely that these trees either show expansion <2-fold, or the baseline used to average is affecting expansion - e.g. if the baseline was higher at the start of the decline, expansion would not be detected.


Extract individual sublineages for Bayesian Skyline analysis (only take sublineages of decent size, with no outgroups)

major.multicountry.sublineages <- sublineage.counts[sublineage.counts$Count>10,]
major.multicountry.sublineages
sublineage.1.meta <- TPA.meta1.2.pinecone[TPA.meta1.2.pinecone$TPA.pinecone.sublineage==1,c("Cleaned_fastq_id","Sample_Name","Sample_Year")]
sublineage.2.meta <- TPA.meta1.2.pinecone[TPA.meta1.2.pinecone$TPA.pinecone.sublineage==2,c("Cleaned_fastq_id","Sample_Name","Sample_Year")]
#sublineage.4.meta <- TPA.meta1.2.pinecone[TPA.meta1.2.pinecone$TPA.pinecone.sublineage==4,c("Cleaned_fastq_id","Sample_Name","Sample_Year")]
sublineage.8.meta <- TPA.meta1.2.pinecone[TPA.meta1.2.pinecone$TPA.pinecone.sublineage==8,c("Cleaned_fastq_id","Sample_Name","Sample_Year")]
sublineage.14.meta <- TPA.meta1.2.pinecone[TPA.meta1.2.pinecone$TPA.pinecone.sublineage==14,c("Cleaned_fastq_id","Sample_Name","Sample_Year")]

all.pinecone.meta <- TPA.meta1.2.pinecone.havedates[,c("Cleaned_fastq_id","Sample_Name","Sample_Year")]

Check temporal signal by extracting subtrees


p.sublin.1.r2t <- plot.subtree.R2T(TPA.MLtree,sublineage.1.meta$Sample_Name,TPA.meta1.2.pinecone.havedates[,c("Sample_Name","Sample_Year")])
p.sublin.2.r2t <- plot.subtree.R2T(TPA.MLtree,sublineage.2.meta$Sample_Name,TPA.meta1.2.pinecone.havedates[,c("Sample_Name","Sample_Year")])
p.sublin.8.r2t <- plot.subtree.R2T(TPA.MLtree,sublineage.8.meta$Sample_Name,TPA.meta1.2.pinecone.havedates[,c("Sample_Name","Sample_Year")])
p.sublin.14.r2t <- plot.subtree.R2T(TPA.MLtree,sublineage.14.meta$Sample_Name,TPA.meta1.2.pinecone.havedates[,c("Sample_Name","Sample_Year")])



#Cairo::Cairo(file=paste0(Figure_output_directory, "Supplementary_Figure10_Sublineages_trees+root2tip__02-2021.svg"), width = 1000, height = 1000,type="svg",units = "pt")
plot_grid(p.sublin.1.r2t,p.sublin.2.r2t,p.sublin.8.r2t,p.sublin.14.r2t,ncol=2, labels=c('Sublineage 1','Sublineage 2','Sublineage 8','Sublineage 14'),scale = 0.85,label_size=12)

#dev.off()

Evaluate subtree skyline analyses

Sublineage 1 (new)
Seqs 365, sites 278, span 1981-2019
- Good convergence in all traces, strong ESS for most variables, but lower for a few of the skyline groups (ESS>100, apart from Skyline.Groupsize10 with ESS 79)
- clock rate 1.34e-7

Sublineage 2 (new)
Seqs 32, sites 36, span 2000-2019
- Good convergence in all traces, very strong ESS in all cases
- Skyline strong expanding skyline plot
- clock rate 1.57e-7

Sublineage 8 (new)
Seqs 15, sites 31, span 1986-2019
- Good convergence in all traces, very strong ESS in all cases
- Skyline - good skyline, showing possible expansion during 90s, possible contraction in 2010s)
- clock rate 1.80e-7

Sublineage 14 (new)
Seqs 55, sites 23, span 2013-2019
- did not converge (at all)
- No temporal signal (in r2t plots)




Define some functions to plot



plot.skyline.data <- function(skyline.file,lineages.file){  
  skyline.data <- read.table(paste0(sublineage.skylines.filepath,skyline.file), header=T, sep="\t", comment.char="",stringsAsFactors=F)
  skyline.plot <- ggplot(skyline.data, aes(Time,Median)) + 
    geom_line() + geom_ribbon(aes(ymin=Lower, ymax=Upper), alpha=0.2, fill='black') +
    theme_light() + 
    #scale_x_continuous(breaks=c(seq(1740,2020,20)), expand=c(0.01,0.01)) + 
    scale_x_continuous(breaks=c(seq(1980,2020,20)), expand=c(0.01,0.01)) + 
    scale_y_log10() + 
    coord_cartesian(x=c(1980,2020)) + 
    theme.text.size + labs(y="Relative genetic diversity", x="Year") + 
    geom_vline(xintercept = 2000, color='blue', alpha=0.5) + annotate("rect",xmin=2000,xmax=2020,ymin=0,ymax=10000,alpha=0.1, fill='blue')
  
  # Lineages
  skyline.lineages <- read.table(paste0(sublineage.skylines.filepath,lineages.file), header=T, sep="\t", comment.char="",stringsAsFactors=F)
  lineages.plot  <- ggplot(skyline.lineages, aes(Time,Median)) + 
    geom_line() + geom_ribbon(aes(ymin=Lower, ymax=Upper), alpha=0.2, fill='black') +
    theme_light() + 
    scale_x_continuous(breaks=c(seq(1980,2020,20)), expand=c(0.01,0.01)) + 
    #scale_x_continuous(breaks=c(seq(1740,2020,20)), expand=c(0.01,0.01)) + 
    scale_y_log10() + 
    coord_cartesian(x=c(1980,2020), y=c(1,300)) + 
    #scale_x_continuous(breaks=c(seq(1740,2020,20)), expand=c(0.01,0.01)) + 
    theme.text.size + labs(y="Lineages", x="Year") + 
    geom_vline(xintercept = 2000, color='blue', alpha=0.5) + annotate("rect",xmin=2000,xmax=2020,ymin=0,ymax=500,alpha=0.1, fill='blue')
  
  skyline.combined.plot <- plot_grid(skyline.plot,lineages.plot, ncol=1, align=T)
  return(skyline.combined.plot)
  #return(skyline.plot)
}

Plot sublineage skylines with lineages through time - all together


sublineage.skylines.filepath <- "/Users/mb29/Treponema/Expanded_Global_Sequencing/Analysis/Global_TPA_uber-analysis_2020_v2/phylo/good_cov_dataset/gubbins_2.4.1__20-11-10/beast/individual_sublineages_reclassified__2021-02-04/beauti/outputs/"
  
collected.skylines <- NULL
for (sublineage in c(1,2,8)) {
  sublineage.skyline <- read.table(paste0(sublineage.skylines.filepath,"TPA-uber.remasked.2020-11-10.goodcov25.gubbins.WGS.sublineage.new.",sublineage,".noinv.Strict-Skyline_combined.skyline-data.tsv"), header=T, sep="\t", comment.char="",stringsAsFactors=F)
  sublineage.skyline$sublineage <- sublineage 
  collected.skylines <- rbind(collected.skylines, sublineage.skyline)
}
beast2.full.skyline$sublineage <- "All"
collected.skylines.inc.full <- rbind(collected.skylines, beast2.full.skyline)
collected.skylines.inc.full$sublineage <- factor(collected.skylines.inc.full$sublineage, levels=unique(collected.skylines.inc.full$sublineage))

sublineage.skyline.combi.plot <- ggplot(collected.skylines.inc.full, aes(Time,Median)) + 
  geom_line() + geom_ribbon(aes(ymin=Lower, ymax=Upper), alpha=0.2, fill='black') +
  theme_light() + 
  #scale_x_continuous(breaks=c(seq(1740,2020,20)), expand=c(0.01,0.01)) + 
  scale_x_continuous(breaks=c(seq(1740,2020,20)), expand=c(0.01,0.01)) + 
  scale_y_log10() + 
  coord_cartesian(x=c(1900,2020),y=c(1,3000)) + 
  theme.text.size + labs(y="Relative genetic diversity (per sublineage)", x="Year") + 
  geom_vline(xintercept = 2000, color='blue', alpha=0.5) + #annotate("rect",xmin=2000,xmax=2020,ymin=0,ymax=10000,alpha=0.1, fill='blue') + 
  facet_grid(sublineage~.) +
  theme(strip.background = element_rect(color='white', fill='white',linetype="solid"), strip.text.y=element_text(color = "grey25",angle=0, size=10))


# Do same for 'lineages through time'
collected.skylines.lineages <- NULL
for (sublineage in c(1,2,8)) {
  sublineage.skyline.lineages <- read.table(paste0(sublineage.skylines.filepath,"TPA-uber.remasked.2020-11-10.goodcov25.gubbins.WGS.sublineage.new.",sublineage,".noinv.Strict-Skyline_combined.lineages-data.tsv"), header=T, sep="\t", comment.char="",stringsAsFactors=F)
  sublineage.skyline.lineages$sublineage <- sublineage 
  collected.skylines.lineages <- rbind(collected.skylines.lineages, sublineage.skyline.lineages)
}
beast2.full.lineages$sublineage <- "All"
collected.skylines.lineages.inc.full <- rbind(collected.skylines.lineages, beast2.full.lineages)
collected.skylines.lineages.inc.full$sublineage <- factor(collected.skylines.lineages.inc.full$sublineage, levels=unique(collected.skylines.lineages.inc.full$sublineage))


sublineage.skyline.lineages.combi.plot <- ggplot(collected.skylines.lineages.inc.full, aes(Time,Median)) + 
  geom_line() + geom_ribbon(aes(ymin=Lower, ymax=Upper), alpha=0.2, fill='black') +
  theme_light() + 
  scale_x_continuous(breaks=c(seq(1980,2020,10)), expand=c(0.01,0.01)) + 
  scale_y_log10() + 
  coord_cartesian(x=c(1980,2020)) + 
  theme.text.size + labs(y="Inferred Lineages (per sublineage)", x="Year") + 
  geom_vline(xintercept = 2000, color='blue', alpha=0.5) + #annotate("rect",xmin=2000,xmax=2020,ymin=0,ymax=10000,alpha=0.1, fill='blue') + 
  facet_grid(sublineage~.) +
  theme(strip.background = element_rect(color='white', fill='white',linetype="solid"), strip.text.y=element_text(color = "grey25",angle=0, size=10))


#Cairo::Cairo(file=paste0(Figure_output_directory, "Supplementary_Figure9_sublineages_skylines__02-2021.svg"), width = 300, height = 400,type="svg",units = "pt")
sublineage.skyline.combi.plot

#dev.off()

Look at Chris Ruis’s tool for extracting the date distributino of a population size increase
Run as:
python3 ~/scripts/population_increase_distribution_BEAST.py -b1 -t TPA-uber.remasked.2020-11-10.goodcov25.gubbins.WGS.sublineage.12.Strict-Skyline_combined.trees -l TPA-uber.remasked.2020-11-10.goodcov25.gubbins.WGS.sublineage.12.Strict-Skyline_combined.log -d 2019.5 -o TPA-uber.remasked.2020-11-10.goodcov25.gubbins.WGS.sublineage.12.Strict-Skyline_combined.pop-distributions.txt

All pop distros

# "TPA-uber_beast2_strict-skyline-500M_10pop_combined.pop-distributions_p100.txt"
pop.distro.subsampled.all.file <- beast2.full.popdistro.path 


# Do same for 'lineages through time'
collected.skyline.popdistros <- NULL
for (sublineage in c(1,2,8)) {
  skyline.popdistro <- read.table(paste0(pop.distro.path,"TPA-uber.remasked.2020-11-10.goodcov25.gubbins.WGS.sublineage.new.",sublineage,".noinv.Strict-Skyline_combined.pop-expansion"), header=T, sep="\t", comment.char="",stringsAsFactors=F)
  skyline.popdistro$sublineage <- sublineage 
  collected.skyline.popdistros <- rbind(collected.skyline.popdistros, skyline.popdistro)
}
# do 'All' separately
sublineage.all.skyline.pop.distro <- read.table(paste0(pop.distro.path,pop.distro.subsampled.all.file), header=T, sep="\t", comment.char="",stringsAsFactors=F)
sublineage.all.skyline.pop.distro$sublineage <- "All"
collected.skyline.popdistros <- rbind(collected.skyline.popdistros,sublineage.all.skyline.pop.distro)


collected.skyline.popdistros$sublineage <- factor(collected.skyline.popdistros$sublineage, levels=unique(collected.skyline.popdistros$sublineage))

x.theme.strip.partial <- theme(axis.text.x = element_blank(), axis.ticks.x= element_blank())


plot.collected.skyline.popdistros.starts <- ggplot(collected.skyline.popdistros[collected.skyline.popdistros$Increase_date>0,], aes(sublineage,Increase_date)) +
  geom_sina(alpha=0.2,color="grey80", size=1) + 
  geom_boxplot(alpha=0.0,outlier.shape = NA, width=0.25) +
  coord_cartesian(ylim=c(1900,2020)) + 
  theme_light() + 
  ylim(1940,2020) +
  facet_grid(sublineage~., scales="free_y") +
  coord_flip() + theme.text.size +
  theme(strip.background = element_rect(color='white', fill='white',linetype="solid"), strip.text.y=element_text(color = "grey25",angle=0, size=10)) +
  #y.theme.strip +
  theme(axis.text.y=element_blank(), axis.ticks.y=element_blank()) +
  labs(y="Year", x="Distribution density (start date for 5-fold population expansion)") + 
  geom_hline(yintercept = 2000, color='blue', alpha=0.5) +
  NULL
Coordinate system already present. Adding new coordinate system, which will replace the existing one.
#plot.collected.skyline.popdistros.starts


plot.collected.skyline.popdistros.starts.density <- ggplot(collected.skyline.popdistros[collected.skyline.popdistros$Increase_date>0,], aes(Increase_date)) + 
  geom_density() +
  coord_cartesian(xlim=c(1900,2020)) +
  #scale_x_continuous(breaks=c(seq(1740,2020,20)), expand=c(0.01,0.01), limits=c(1740,2020)) + 
  scale_x_continuous(breaks=c(seq(1740,2020,20)), expand=c(0.01,0.01)) + 
  facet_grid(sublineage~., scales="free_y") +
  #facet_grid(sublineage~.) +
  theme_light() + 
  theme.text.size + 
  #theme(axis.text.y=element_blank(), axis.ticks.y=element_blank()) +
  theme(strip.background = element_rect(color='white', fill='white',linetype="solid"), strip.text.y=element_text(color = "grey25",angle=0, size=10)) +
  labs(x="Year", y="Distribution density (start of 2-fold population expansion)") + 
  geom_vline(xintercept = 2000, color='blue', alpha=0.5) +
  NULL
plot.collected.skyline.popdistros.starts.density


plot_grid(sublineage.skyline.combi.plot,  sublineage.skyline.lineages.combi.plot, plot.collected.skyline.popdistros.starts.density,ncol=3, align=T, axis="ltb",rel_widths=c(4,2,3), labels=c('A - Genetic Diversity','B - Lineages','C - Population Expansion'), label_size=11,label_y=1, label_x=0.01, scale=0.95) 


#Want to look at distributions within single countries

Extract UK and Canada (all) subtrees


subtree.UK.meta <- TPA.meta1.2.pinecone[(TPA.meta1.2.pinecone$Geo_Country=="UK"),c("Cleaned_fastq_id","Sample_Name","Sample_Year")]
p.subtree.UK.r2t <- plot.subtree.R2T(TPA.MLtree,subtree.UK.meta$Sample_Name,TPA.meta1.2.pinecone.havedates[,c("Sample_Name","Sample_Year")])
`geom_smooth()` using formula 'y ~ x'
subtree.BC.meta <- TPA.meta1.2.pinecone[(TPA.meta1.2.pinecone$Geo_Region=="British_Columbia"),c("Cleaned_fastq_id","Sample_Name","Sample_Year")]
p.subtree.BC.r2t <- plot.subtree.R2T(TPA.MLtree,subtree.BC.meta$Sample_Name,TPA.meta1.2.pinecone.havedates[,c("Sample_Name","Sample_Year")])
`geom_smooth()` using formula 'y ~ x'
plot_grid(p.subtree.UK.r2t, p.subtree.BC.r2t, nrow=2)

Extract UK and Canada subtrees for Sublineage 2 only


sublineage.2.UK.meta <- TPA.meta1.2.pinecone[(TPA.meta1.2.pinecone$TPA.pinecone.sublineage==2 & TPA.meta1.2.pinecone$Geo_Country=="UK"),c("Cleaned_fastq_id","Sample_Name","Sample_Year")]
p.sublin.2.UK.r2t <- plot.subtree.R2T(TPA.MLtree,sublineage.2.UK.meta$Sample_Name,TPA.meta1.2.pinecone.havedates[,c("Sample_Name","Sample_Year")])
`geom_smooth()` using formula 'y ~ x'
sublineage.2.BC.meta <- TPA.meta1.2.pinecone[(TPA.meta1.2.pinecone$TPA.pinecone.sublineage==2 & TPA.meta1.2.pinecone$Geo_Region=="British_Columbia"),c("Cleaned_fastq_id","Sample_Name","Sample_Year")]
p.sublin.2.BC.r2t <- plot.subtree.R2T(TPA.MLtree,sublineage.2.BC.meta$Sample_Name,TPA.meta1.2.pinecone.havedates[,c("Sample_Name","Sample_Year")])
`geom_smooth()` using formula 'y ~ x'
plot_grid(p.sublin.2.UK.r2t, p.sublin.2.BC.r2t, nrow=2)

So very little temporal signal here, particularly for the UK data (only 7 years). Not realistic to analyse this way.

Look at coverage statistics

# For the large low cov dataset
nrow(TPA.meta1.2)
[1] 726
mean(as.numeric(TPA.meta1.2$Mean_mapping_coverage), na.rm=T)
[1] 84.41708
max(as.numeric(TPA.meta1.2$Mean_mapping_coverage))
[1] 727.8
min(as.numeric(TPA.meta1.2$Mean_mapping_coverage))
[1] 3.1
(1-mean(as.numeric(TPA.meta1.2$`Proportion-N_>5_mapping+masking_Nichols`), na.rm=T))*100
[1] 82.088
(1-max(as.numeric(TPA.meta1.2$`Proportion-N_>5_mapping+masking_Nichols`), na.rm=T))*100
[1] 25.0359
(1-min(as.numeric(TPA.meta1.2$`Proportion-N_>5_mapping+masking_Nichols`), na.rm=T))*100
[1] 96.92742
# For the curated dataset
nrow(TPA.meta1.2.pinecone)
[1] 528
mean(as.numeric(TPA.meta1.2.pinecone$Mean_mapping_coverage), na.rm=T)
[1] 111.0958
max(as.numeric(TPA.meta1.2.pinecone$Mean_mapping_coverage))
[1] 727.8
min(as.numeric(TPA.meta1.2.pinecone$Mean_mapping_coverage))
[1] 11.1
(1-mean(as.numeric(TPA.meta1.2.pinecone$`Proportion-N_>5_mapping+masking_Nichols`), na.rm=T))*100
[1] 92.89512
(1-max(as.numeric(TPA.meta1.2.pinecone$`Proportion-N_>5_mapping+masking_Nichols`), na.rm=T))*100
[1] 75.0879
(1-min(as.numeric(TPA.meta1.2.pinecone$`Proportion-N_>5_mapping+masking_Nichols`), na.rm=T))*100
[1] 96.92742

Quickly look at lineage association of recombination blocks

# Define and read in recombination info
recombination_event.data <- readxl::read_excel(recombination_event.file,sheet="Recombination_Data")

# Subset to gubbins filtered regions and order by event
recombination_event.data.gubbins <- recombination_event.data[recombination_event.data$Gubbins_Event_ID!="-",]
recombination_event.data.gubbins <- recombination_event.data.gubbins[!is.na(recombination_event.data.gubbins$line_order),]
recombination_event.data.gubbins <- recombination_event.data.gubbins[order(as.numeric(recombination_event.data.gubbins$Gubbins_Event_ID)),]

# convert per-event list into a matrix
recombination_event.data.gubbins.matrix <- reshape2::dcast(reshape2::melt(strsplit(recombination_event.data.gubbins$SampleIDs,",")),L1~value)
colnames(recombination_event.data.gubbins.matrix)[1] <- "Gubbins_Event_ID"

# melt matrix into longform
recombination_event.data.gubbins.matrix.melt <- reshape2::melt(recombination_event.data.gubbins.matrix,id.vars="Gubbins_Event_ID")
# infer presence/absence
recombination_event.data.gubbins.matrix.melt$binary <- ifelse(is.na(recombination_event.data.gubbins.matrix.melt$value),0,1)
colnames(recombination_event.data.gubbins.matrix.melt) <- c("Gubbins_Event_ID","Sample_Name","value","recomb.present")

# Make a binary presence/absence matrix organised by sample (for possible plotting with ggtree)
recombination_event.data.gubbins.matrix.binary <- reshape2::dcast(recombination_event.data.gubbins.matrix.melt[,c("Gubbins_Event_ID","Sample_Name","recomb.present")], Sample_Name~Gubbins_Event_ID)
Using recomb.present as value column: use value.var to override.
# Merge in Lineage and Pinecone information
recombination_event.data.gubbins.matrix.melt <- plyr::join(recombination_event.data.gubbins.matrix.melt[c("Gubbins_Event_ID","Sample_Name","recomb.present")],TPA.meta1.2.pinecone[,c("Sample_Name","TPA.pinecone.sublineage","TPA_Lineage")], by="Sample_Name")


recombination_event.by.Lineage <- recombination_event.data.gubbins.matrix.melt %>% dplyr::group_by(Gubbins_Event_ID, TPA_Lineage) %>% 
  dplyr::summarise(Sum=sum(recomb.present))
`summarise()` regrouping output by 'Gubbins_Event_ID' (override with `.groups` argument)
#recombination_event.by.Lineage[recombination_event.by.Lineage$Sum!=0,]

recombination_event.by.sublineage <- recombination_event.data.gubbins.matrix.melt %>% dplyr::group_by(Gubbins_Event_ID, TPA.pinecone.sublineage) %>% 
  dplyr::summarise(Sum=sum(recomb.present))
`summarise()` regrouping output by 'Gubbins_Event_ID' (override with `.groups` argument)
recombination_event.by.sublineage[recombination_event.by.sublineage$Sum!=0,]
NA
NA
recombination_event.data.gubbins.matrix.melt <- plyr::join(recombination_event.data.gubbins.matrix.melt, recombination_event.data.gubbins[,c("Gubbins_Event_ID","Block_Start","Block_End")], by="Gubbins_Event_ID")

recombiplot.tip.order <- data.frame(Sample_Name=get_taxa_name(ggtree(TPA.MLtree)),stringsAsFactors = F) 
recombiplot.tip.order$order <- c(1:nrow(recombiplot.tip.order))
recombiplot.tip.order$order2 <- rev(c(1:nrow(recombiplot.tip.order)))
recombiplot.tip.order <- plyr::join(recombiplot.tip.order,recombination_event.data.gubbins.matrix.melt, by="Sample_Name", type="full")


p.recombi.plot <- ggplot(recombiplot.tip.order) +
  geom_rect(aes(ymin=order2-0.5,ymax=order2+0.5, xmin=as.numeric(Block_Start), xmax=as.numeric(Block_End)), alpha=0.5) +
  coord_cartesian(xlim=c(1,1139569)) +
  theme_minimal()

#TPA.MLtree.ggtree.tippoint


#ggtree(TPA.MLtree) + theme(legend.position="none")
plot_grid(ggtree(TPA.MLtree), p.recombi.plot, align=T, axis="tb", rel_widths = c(1,2))
Removed 73 rows containing missing values (geom_rect).


TPA.MLtree.testplot <- ggtree(TPA.MLtree)
#facet_plot(TPA.MLtree.testplot, panel="Genome_Blocks", data=recombiplot.tip.order, geom_rect, mapping=aes(xmin=Block_Start, xmax=Block_End, fill=TPA_Lineage))
recombining.genes <- c("TPASS_RS00040", "TPASS_RS00045", "TPASS_RS00590", "TPASS_RS00675", "TPASS_RS01555", "TPASS_RS01565", "TPASS_RS01570", "TPASS_RS02125", "TPASS_RS02290", "TPASS_RS02700", "TPASS_RS03020", "TPASS_RS03070", "TPASS_RS03075", "TPASS_RS04240", "TPASS_RS04245", "TPASS_RS04250", "TPASS_RS04275", "TPASS_RS05385", "TPASS_RS05110", "TPASS_RS05210,TPASS_RS00685,TPASS_RS00705,TPASS_RS00690,TPASS_RS00680,TPASS_RS00700,TPASS_RS00675,TPASS_RS00665,TPASS_RS00670", "TPASS_RS00705,TPASS_RS00685,TPASS_RS00690,TPASS_RS00700", "TPASS_RS00705", "TPASS_RS00705", "TPASS_RS00705", "TPASS_RS00905", "TPASS_RS01600", "TPASS_RS01600", "TPASS_RS02265", "TPASS_RS02265", "TPASS_RS02265", "TPASS_RS02350,TPASS_RS02355", "TPASS_RS02375", "TPASS_RS02525", "TPASS_RS02760,TPASS_RS02755", "TPASS_RS03055,TPASS_RS03065,TPASS_RS03060", "TPASS_RS03065", "TPASS_RS04780,TPASS_RS04790,TPASS_RS04785,TPASS_RS04775", "TPASS_RS05100,TPASS_RS05105")


recombining.genes <- c("TPASS_RS05210,TPASS_RS00685,TPASS_RS00705,TPASS_RS00690,TPASS_RS00680,TPASS_RS00700,TPASS_RS00675,TPASS_RS00665,TPASS_RS00670", "TPASS_RS00705,TPASS_RS00685,TPASS_RS00690,TPASS_RS00700", "TPASS_RS00705", "TPASS_RS00705", "TPASS_RS00705", "TPASS_RS00905", "TPASS_RS01600", "TPASS_RS01600", "TPASS_RS02265", "TPASS_RS02265", "TPASS_RS02265", "TPASS_RS02350,TPASS_RS02355", "TPASS_RS02375", "TPASS_RS02525", "TPASS_RS02760,TPASS_RS02755", "TPASS_RS03055,TPASS_RS03065,TPASS_RS03060", "TPASS_RS03065", "TPASS_RS04780,TPASS_RS04790,TPASS_RS04785,TPASS_RS04775", "TPASS_RS05100,TPASS_RS05105")

unique(unlist(strsplit(recombining.genes,",")))
 [1] "TPASS_RS05210" "TPASS_RS00685" "TPASS_RS00705" "TPASS_RS00690" "TPASS_RS00680" "TPASS_RS00700" "TPASS_RS00675" "TPASS_RS00665"
 [9] "TPASS_RS00670" "TPASS_RS00905" "TPASS_RS01600" "TPASS_RS02265" "TPASS_RS02350" "TPASS_RS02355" "TPASS_RS02375" "TPASS_RS02525"
[17] "TPASS_RS02760" "TPASS_RS02755" "TPASS_RS03055" "TPASS_RS03065" "TPASS_RS03060" "TPASS_RS04780" "TPASS_RS04790" "TPASS_RS04785"
[25] "TPASS_RS04775" "TPASS_RS05100" "TPASS_RS05105"

Tip date randomisation using TipDatingBEAST package

library(TipDatingBeast)

# setwd("/Users/mb29/Treponema/Expanded_Global_Sequencing/Analysis/Global_TPA_uber-analysis_2020_v2/phylo/good_cov_dataset/gubbins_2.4.1__20-11-10/beast/beast2_full-tree_2020-11-25/beauti/tip_randomisation/")

#setwd("/Users/mb29/Treponema/Expanded_Global_Sequencing/Analysis/Global_TPA_uber-analysis_2020_v2/phylo/good_cov_dataset/gubbins_2.4.1__20-11-10/beast/beast2_full-tree_2020-11-25/beauti/tip_randomisation/rerun_MEL-1_01-03-2021/")

original.xml.file <- "beast2_Strict-Skyline_Full500M_+sites_1"

# Generate tipdate-randomised xml files from original BEAST2 xml
#TipDatingBeast::RandomDates(name="beast2_Strict-Skyline_Full500M_+sites_1",reps=20)

# All datasets run in BEAST2. 

# After 20 runs (took ~2 weeks) ensure all files are correctly labelled and pull in data
#TipDatingBeast::PlotDRT(name="beast2_Strict-Skyline_Full500M_+sites_1",reps=20,burnin=0.1)

# That plot isn't very nice, but the package also generates a csv file containing the values of interest that we can plot

randomtip.summary <- read.csv(random.tip.summary.file,header=T)

randomtip.summary$Data <- ifelse(randomtip.summary$calibr==0,"Real","Randomised")

p.tipdaterandomisation.normal <- ggplot(randomtip.summary) +
  geom_pointrange(aes(x=calibr, y=median,ymin = lowerHPD, ymax = HigherHPD,color=Data)) +
  theme_light() + theme(legend.position="top") +
  labs(x="Replicate", y="Clock Rate") +
  geom_hline(yintercept=randomtip.summary$lowerHPD[1],alpha=0.5) +
  geom_hline(yintercept=randomtip.summary$HigherHPD[1],alpha=0.5) +
  geom_hline(yintercept=randomtip.summary$HigherHPD[18],alpha=0.5) +
  NULL
#p.tipdaterandomisation.normal

p.tipdaterandomisation.log10 <- ggplot(randomtip.summary) +
  geom_pointrange(aes(x=calibr, y=median,ymin = lowerHPD, ymax = HigherHPD,color=Data)) +
  theme_light() + 
  theme(legend.position="top") +
  #scale_y_log10() +
  scale_y_log10(breaks = trans_breaks("log10", function(x) 10^x),
              labels = trans_format("log10", math_format(10^.x))) +
  labs(x="Replicate", y="Clock Rate") +
  geom_hline(yintercept=randomtip.summary$lowerHPD[1],alpha=0.5) +
  geom_hline(yintercept=randomtip.summary$HigherHPD[1],alpha=0.5) +
  NULL

#Cairo::Cairo(file=paste0(Figure_output_directory, "Supplementary_Figure19_tipdate-randomisation.svg"), width = 550, height = 300,type="svg",units = "pt")
p.tipdaterandomisation.log10

#dev.off()

randomtip.summary[randomtip.summary$calibr==0,"median"]
[1] 1.274125e-07
max(randomtip.summary[randomtip.summary$calibr!=0,"median"])
[1] 8.016449e-09

Distribution of Rabbit passaged strains


sublineage.passaged.samples <- data.frame(TPA.meta1.2.pinecone %>% dplyr::group_by(TPA.pinecone.sublineage,Direct_from_clin) %>%
  dplyr::summarise(count=n()),stringsAsFactors = F)
`summarise()` regrouping output by 'TPA.pinecone.sublineage' (override with `.groups` argument)
sublineage.passaged.samples$TPA.pinecone.sublineage <- factor(sublineage.passaged.samples$TPA.pinecone.sublineage, levels=rev(sublineages.cols.brew$sublineage))

p.sublineage.rabbit.passage <- ggplot(sublineage.passaged.samples, aes(count, TPA.pinecone.sublineage, fill=Direct_from_clin)) +
  geom_barh(stat="identity",position="fill", width=0.75) +
  theme_light() +
  theme.text.size + theme(legend.key.size = unit(0.65,"line"),legend.position='bottom') +
  scale_fill_manual(name="Direct from Clinical sample\n(no rabbit passage)",values=c("grey80","grey10")) +
  labs(y="Sublineage", x="Proportion passaged")

#p.sublineage.rabbit.passage


#data.frame(row.names=TPA.meta1.2.pinecone$Sample_Name, Direct_Sequenced=TPA.meta1.2.pinecone$Direct_from_clin, stringsAsFactors=F)

p.MLtree.rabbit.passage.distros <- gheatmap(TPA.MLtree.ggtree.tippoint + theme(legend.position="none"),
               data.frame(row.names=TPA.meta1.2.pinecone$Sample_Name, `Direct from clinical`=TPA.meta1.2.pinecone$Direct_from_clin, stringsAsFactors=F), color='grey70',width=0.075,offset=0.00000725, colnames_angle=-45,colnames_offset_y=0, hjust=0,font.size=2) + 
  scale_fill_manual(name="Direct from clinical sample",values=c("grey80","grey10")) +
  theme.text.size + theme(legend.key.size = unit(0.65,"line"),legend.position='right')
Scale for 'fill' is already present. Adding another scale for 'fill', which will replace the existing scale.
p.sublineage.rabbit.passage.toprow <- plot_grid('',p.sublineage.rabbit.passage + theme(legend.position='none'),'',ncol=1,rel_heights=c(1,3,1))
Cannot convert object of class character into a grob.Cannot convert object of class character into a grob.
p.rabbit.passage.distros.combination <- plot_grid(p.MLtree.rabbit.passage.distros, p.sublineage.rabbit.passage.toprow, rel_widths = c(3,1), labels=c('A','B'), label_size=11)


#Cairo::Cairo(file=paste0(Figure_output_directory, "Supplementary_Figure7__MLtree+rabbitpassage_02-2021.svg"), width = 1000, height = 800,type="svg",units = "pt")
p.rabbit.passage.distros.combination

#dev.off()





Look at distribution of SNPs on genome



WGS.site.positions <- read.table(WGS.site.positions.file, stringsAsFactors = F, header=F)
colnames(WGS.site.positions) <- "position"

ggplot(WGS.site.positions, aes(position)) + 
  geom_density() +
  theme_light()


WGS.site.positions$SNP <- 1
WGS.site.positions.all <- plyr::join(WGS.site.positions, data.frame(position=c(1:1139569),stringsAsFactors=F), type="right", by="position")
WGS.site.positions.all[is.na(WGS.site.positions.all$SNP),"SNP"] <- 0


windowsize <- 1000
WGS.site.positions.all$window <- ((trunc(as.numeric(WGS.site.positions.all$position) / windowsize,0))*windowsize)
WGS.SNP.density.window <- WGS.site.positions.all %>% 
  group_by(window) %>% 
  dplyr::summarise(mean = mean(SNP), count=sum(SNP))
`summarise()` ungrouping output (override with `.groups` argument)
p.WGS.SNP.density <- ggplot(WGS.SNP.density.window, aes(window, count)) + 
  geom_point(alpha=0.5) +
  theme_light() + 
  labs(x=paste0("Genome Position (",windowsize," bp windows)"), y=paste0("Variable sites/",windowsize," bp")) +
  theme.text.size
p.WGS.SNP.density

NA
NA
NA
NA

Bring macrolide resistance back in

Look at macrolide resistance



TPA.global.compmapping.23s <- read.table(TPA.global.compmapping.23s.file, header=T, sep="\t", check.names = F, comment.char = "")


# Missing tree samples from 23s data
missing.23S <- TPA.MLtree$tip.label[TPA.MLtree$tip.label %notin% TPA.global.compmapping.23s$Sample] 
missing.23S.meta <- TPA.meta1.2.pinecone[TPA.meta1.2.pinecone$Sample_Name %in% missing.23S, "Cleaned_fastq_id"]

# Only keep relevant values
TPA.global.compmapping.23s <- TPA.global.compmapping.23s[TPA.global.compmapping.23s$Sample %in% TPA.MLtree$tip.label,]


TPA.global.compmapping.23s$Sample_Name <- TPA.global.compmapping.23s$Sample

# Evaluate alleles (again)
TPA.global.compmapping.23s$VariantPresent_A2058G_redo <- ifelse((TPA.global.compmapping.23s$ALT_A2058G=="G" & TPA.global.compmapping.23s$DP_A2058G>20 & TPA.global.compmapping.23s$AltPerc_A2058G>95),"Yes", ifelse(TPA.global.compmapping.23s$VariantPresent_A2058G=="Hetero","Uncertain",ifelse((TPA.global.compmapping.23s$ALT_A2058G=="G" & TPA.global.compmapping.23s$DP_A2058G<=20 & TPA.global.compmapping.23s$AltPerc_A2058G>95),"Uncertain","No")))

TPA.global.compmapping.23s$VariantPresent_A2059G_redo <- ifelse((TPA.global.compmapping.23s$ALT_A2059G=="G" & TPA.global.compmapping.23s$DP_A2059G>20 & TPA.global.compmapping.23s$AltPerc_A2059G>95),"Yes", ifelse(TPA.global.compmapping.23s$VariantPresent_A2059G=="Hetero","Uncertain",ifelse((TPA.global.compmapping.23s$ALT_A2059G=="G" & TPA.global.compmapping.23s$DP_A2059G<=20 & TPA.global.compmapping.23s$AltPerc_A2058G>95),"Uncertain","No")))


TPA.global.compmapping.23s$resistant <- ifelse((TPA.global.compmapping.23s$VariantPresent_A2058G_redo=="Hetero" | TPA.global.compmapping.23s$VariantPresent_A2059G_redo=="Uncertain"),"Uncertain",ifelse(TPA.global.compmapping.23s$VariantPresent_A2058G_redo=="Yes" & TPA.global.compmapping.23s$VariantPresent_A2059G_redo=="No", "A2058G", ifelse(TPA.global.compmapping.23s$VariantPresent_A2058G_redo=="No" & TPA.global.compmapping.23s$VariantPresent_A2059G_redo=="Yes","A2059G", ifelse(TPA.global.compmapping.23s$VariantPresent_A2058G_redo=="No" & TPA.global.compmapping.23s$VariantPresent_A2059G_redo=="No", "Sensitive","Uncertain"))))

Now plot in a nice tree


TPA.global.compmapping.23s.p <- data.frame(row.names=TPA.global.compmapping.23s$Sample, A2058G=TPA.global.compmapping.23s$VariantPresent_A2058G_redo, A2059G=TPA.global.compmapping.23s$VariantPresent_A2059G_redo)

p.MLtree.23S.distros <- gheatmap(TPA.MLtree.ggtree.tippoint + theme(legend.position="none"),
               TPA.global.compmapping.23s.p, color='grey70',width=0.075,offset=0.00000725, colnames_angle=-45,colnames_offset_y=0, hjust=0,font.size=2) + 
  #scale_fill_manual(name="Resistance\nAllele\nPresent",values=c("grey50","grey95","black"), breaks=c("Uncertain","No","Yes")) +
  scale_fill_manual(name="Resistance\nAllele\nPresent",values=c("black","grey95","grey50"), breaks=c("Yes","No","Uncertain")) +
  theme.text.size + theme(legend.key.size = unit(0.65,"line"),legend.position='left')

p.MLtree.23S.distros

Look at sublineage distribution

TPA.meta1.2.pinecone.23S <- plyr::join(TPA.meta1.2.pinecone,data.frame(Sample_Name=TPA.global.compmapping.23s$Sample, A2058G=TPA.global.compmapping.23s$VariantPresent_A2058G_redo, A2059G=TPA.global.compmapping.23s$VariantPresent_A2059G_redo), by="Sample_Name")


TPA.meta1.2.pinecone.23S.counts <- data.frame(TPA.meta1.2.pinecone.23S %>% 
                                                dplyr::group_by(TPA.pinecone.sublineage, A2058G, A2059G) %>%
                                                dplyr::summarise(Count=n()),stringsAsFactors = F)
TPA.meta1.2.pinecone.23S.counts <- reshape2::melt(TPA.meta1.2.pinecone.23S.counts,id.vars=c("TPA.pinecone.sublineage","Count"))


TPA.meta1.2.pinecone.23S.counts$TPA.pinecone.sublineage <- factor(TPA.meta1.2.pinecone.23S.counts$TPA.pinecone.sublineage, levels=rev(sublineages.cols.brew$sublineage))

#TPA.meta1.2.pinecone.23S.counts <- TPA.meta1.2.pinecone.23S.counts[TPA.meta1.2.pinecone.23S.counts$TPA.pinecone.sublineage!="Singleton",]

TPA.meta1.2.pinecone.23S.counts$value <- ifelse(TPA.meta1.2.pinecone.23S.counts$value=="Hetero", "Uncertain",TPA.meta1.2.pinecone.23S.counts$value)

# Plot SNPs by sublineage
p.sublineage.23S.compmap <- ggplot(TPA.meta1.2.pinecone.23S.counts, aes(Count, TPA.pinecone.sublineage, fill=value, color=NULL)) +
  geom_barh(stat="identity", position="fill",width=0.75) + 
  facet_grid(.~variable) + 
  theme_light() +
  scale_fill_manual(values=c("black","grey90","grey50"), breaks=c("Yes","No","Uncertain")) +
  theme(strip.background = element_rect(color='white', fill='white',linetype="solid"), strip.text.x=element_text(color = "grey25",angle=0, size=10)) +
  labs(x="Proportion of samples",y="Sublineage", fill="Resistance\nallele\npresent") +
  theme.text.size + theme(legend.key.size = unit(0.75,"line"),legend.position='bottom') 
#p.sublineage.23S.compmap



# Want to include Singletons for this analyis  - Redo country sublineage distros
sublineage.country.counts.incSing <- plyr::join(TPA.meta1.2.pinecone[(TPA.meta1.2.pinecone$Sample_Year!="-"),c("Sample_Name","TPA.pinecone.sublineage")], sublineage.classification, by="TPA.pinecone.sublineage",type="left")
sublineage.country.counts.incSing[is.na(sublineage.country.counts.incSing$private.distro),"private.distro"] <- "Singleton"
sublineage.country.counts.incSing <- sublineage.country.counts.incSing %>% group_by(TPA.pinecone.sublineage, private.distro) %>% summarise(Count=n())
sublineage.country.counts.incSing$TPA.pinecone.sublineage <- factor(sublineage.country.counts.incSing$TPA.pinecone.sublineage,levels=rev(sublineages.cols.brew$sublineage))

p.sublineage.private.hbarplot.incSing <- ggplot(sublineage.country.counts.incSing, aes(Count,TPA.pinecone.sublineage,fill=private.distro)) +
  geom_barh(stat="identity", position="stack", width=0.75) +
  theme_light() +
  #scale_x_log10() +
  coord_cartesian(xlim=c(0,410)) +
  theme.text.size + theme(legend.key.size = unit(0.65,"line"),legend.position='bottom') +
  scale_fill_manual(breaks=(unique(sublineage.country.counts.incSing$private.distro)), values=rev(c("grey80","grey50","grey10"))) +
  labs(y="Sublineage", x="Sample Count", fill="Sublineage\nType") +
  geom_text(data=sublineage.country.counts.incSing, aes((Count+20), TPA.pinecone.sublineage,label=Count), size=2.5, inherit.aes = F)
#p.sublineage.private.hbarplot.incSing


#plot_grid(p.sublineage.hbarplot, p.sublineage.23S.compmap + y.theme.strip, align='h', axis='tb', rel_widths =c(1,2))
p.sublineage.23S.compmap.distributions <- plot_grid(p.sublineage.private.hbarplot.incSing, p.sublineage.23S.compmap + y.theme.strip, align='h', axis='tb', rel_widths =c(1,1))


p.sublineage.23S.compmap.distributions

Plot distros with tree

plot.MLtree.23s.with.sublineage.distros.combo <- plot_grid(p.MLtree.23S.distros, p.sublineage.23S.compmap.distributions, ncol=1, rel_heights=c(3,2), labels=c('A','B'), label_size=11)

#Cairo::Cairo(file=paste0(Figure_output_directory, "Supplementary_Figure14_Sublineage_vs_macrolide-distros__02-2021.svg"), width = 800, height = 1000,type="svg",units = "pt")
plot.MLtree.23s.with.sublineage.distros.combo

#dev.off()

Look at temporal distribution of samples



TPA.meta1.2.pinecone.23s.simpledates <- plyr::join(TPA.meta1.2.pinecone[,c("Sample_Name","TPA.pinecone.sublineage","Sample_Year")],TPA.global.compmapping.23s, by="Sample_Name")

TPA.meta1.2.pinecone.23s.simpledates <- data.frame(TPA.meta1.2.pinecone.23s.simpledates %>% group_by(resistant,TPA.pinecone.sublineage,Sample_Year) %>%
  summarise(Count=n()), stringsAsFactors = F)


TPA.meta1.2.pinecone.23s.simpledates <- TPA.meta1.2.pinecone.23s.simpledates[TPA.meta1.2.pinecone.23s.simpledates$TPA.pinecone.sublineage!="Singleton",]

TPA.meta1.2.pinecone.23s.simpledates <- plyr::join(data.frame(Sample_Year=c(1912:2019),stringsAsFactors=F), TPA.meta1.2.pinecone.23s.simpledates)
TPA.meta1.2.pinecone.23s.simpledates <- TPA.meta1.2.pinecone.23s.simpledates[!is.na(TPA.meta1.2.pinecone.23s.simpledates$TPA.pinecone.sublineage),]
TPA.meta1.2.pinecone.23s.simpledates <- TPA.meta1.2.pinecone.23s.simpledates[!is.na(TPA.meta1.2.pinecone.23s.simpledates$resistant),]



TPA.meta1.2.pinecone.23s.simpledates$TPA.pinecone.sublineage <- factor(TPA.meta1.2.pinecone.23s.simpledates$TPA.pinecone.sublineage, levels=(sublineages.cols.brew$sublineage))


#ggplot(TPA.meta1.2.pinecone.23s.simpledates, aes(Sample_Year, TPA.pinecone.sublineage, color=resistant, size=Count)) +
#  geom_point()

#ggplot(TPA.meta1.2.pinecone.23s.simpledates, aes(Sample_Year, TPA.pinecone.sublineage, color=resistant, size=Count)) +
#  geom_jitter()


p.bubbleplot.sublineage.resistance.alleles <- ggplot(TPA.meta1.2.pinecone.23s.simpledates, aes(Sample_Year, resistant, color=resistant)) +
  geom_point(alpha=0.65, aes(size=Count)) + 
  theme_light() +
  facet_wrap(TPA.pinecone.sublineage~.) +
  coord_cartesian(xlim=c(1970,2020)) + 
  scale_x_continuous(breaks=seq(1970,2020,20)) +
  scale_size_area(max_size = 8,breaks=c(1,5,10,25,50,75,100)) +
  theme(strip.background = element_rect(color='white', fill='white',linetype="solid"), strip.text.x=element_text(color = "grey25",angle=0, size=10)) +
  theme.text.size + theme(legend.key.size = unit(0.75,"line"),legend.position='top') +
  #scale_color_manual(values=c("black","black","grey90","grey50"), breaks=c("A2058G","A2059G","Sensitive","Uncertain"))
  scale_color_manual(name="Resistance\nAllele", values=c("red","blue","black","grey75"), breaks=c("A2058G","A2059G","Sensitive","Uncertain")) +
  geom_vline(xintercept = 2000, color='blue', alpha=0.25) +
  labs(x="Sample Year", y="Resistance Allele")
  
p.bubbleplot.sublineage.resistance.alleles

NA
NA
NA

Look at genetic distance v.s. geographic distance (need to infer geographic distances between samples)

Since specific within-country gps data is limited or unavailable, will infer geographic distance between country centroids (already inferred above for map) - crude but may provide some insights.

Plot together

TPA.alignment.data.dist.melt.meta2 <- plyr::join(TPA.alignment.data.dist.melt.meta,data.frame(Geo_Country.t1=country.coords.subset$Geo_Country, Long1=country.coords.subset$centroid.lon, Lat1=country.coords.subset$centroid.lat, stringsAsFactors = F), type="left", by="Geo_Country.t1")
TPA.alignment.data.dist.melt.meta2 <- plyr::join(TPA.alignment.data.dist.melt.meta2,data.frame(Geo_Country.t2=country.coords.subset$Geo_Country, Long2=country.coords.subset$centroid.lon, Lat2=country.coords.subset$centroid.lat, stringsAsFactors = F), type="left", by="Geo_Country.t2")

# Use geosphere package (distVincentyEllipsoid) to calculate geographic distance between points in km
TPA.alignment.data.dist.melt.meta2$Geographic.Distance <- geosphere::distVincentyEllipsoid(TPA.alignment.data.dist.melt.meta2[,c("Long1","Lat1")],TPA.alignment.data.dist.melt.meta2[,c("Long2","Lat2")])/1000

Now plot

# Genetic Distance v.s. Geographic Distance (same Lineages)
p.geographic.vs.genetic.distance.hex.Lineage <- ggplot(TPA.alignment.data.dist.melt.meta2[TPA.alignment.data.dist.melt.meta2$same.TPA.majorlineage=="same",], aes(Geographic.Distance,Distance)) +
#ggplot(TPA.alignment.data.dist.melt.meta2, aes(Geographic.Distance,Distance)) + 
  stat_bin_hex(colour="white", na.rm=TRUE, bins = 20) +
  scale_fill_gradientn(colours=c("purple","green"), 
                       name = "Comparison Frequency", breaks=c(3,100,3000),
                       na.value=NA, trans="log10") + 
  theme_light() +
  scale_y_continuous(breaks=seq(0,250,10)) +
  labs(y="Pairwise genetic distance (SNPs)", x="Pairwise geographic distance (kilometers)") +
  theme.text.size + theme(legend.key.size = unit(0.75,"line")) +
  theme(strip.background = element_rect(fill='white',linetype="solid"), strip.text.x=element_text(color="grey25", size=10), strip.text.y=element_text(color="grey25", size=10)) +
  theme(legend.position="bottom") +
  #ggtitle("Pairwise SNPs (same sublineage) and Years within and between British Columbia (Canada) and England (UK)") + theme(plot.title = element_text(size = 10)) +
  #facet_grid(TPA_Lineage.t1~same.continent) +
  #facet_grid(.~same.continent) +
  facet_grid(.~TPA_Lineage.t1) +
  NULL
p.geographic.vs.genetic.distance.hex.Lineage <- p.geographic.vs.genetic.distance.hex.Lineage + stat_smooth(method='lm', fullrange=F,se=T, color='black', level=95)

p.geographic.vs.genetic.distance.hex.Lineage

Calculate Pearson’s correlation (for real dataset)

# For whole dataset (but only looking within same Lineage)
real.correlation1 <- cor(TPA.alignment.data.dist.melt.meta2[TPA.alignment.data.dist.melt.meta2$same.TPA.majorlineage=="same","Distance"],TPA.alignment.data.dist.melt.meta2[TPA.alignment.data.dist.melt.meta2$same.TPA.majorlineage=="same","Geographic.Distance"])
real.correlation1
[1] 0.240001
nrow(TPA.alignment.data.dist.melt.meta2[TPA.alignment.data.dist.melt.meta2$same.TPA.majorlineage=="same",])
[1] 191096
# Explicitly By Lineage

# Nichols
real.correlation1.Nichols <- cor(TPA.alignment.data.dist.melt.meta2[(TPA.alignment.data.dist.melt.meta2$same.TPA.majorlineage=="same" & TPA.alignment.data.dist.melt.meta2$TPA_Lineage.t1=="Nichols"),"Distance"],TPA.alignment.data.dist.melt.meta2[(TPA.alignment.data.dist.melt.meta2$same.TPA.majorlineage=="same" & TPA.alignment.data.dist.melt.meta2$TPA_Lineage.t1=="Nichols"),"Geographic.Distance"])
real.correlation1.Nichols
[1] 0.486289
nrow(TPA.alignment.data.dist.melt.meta2[(TPA.alignment.data.dist.melt.meta2$same.TPA.majorlineage=="same" & TPA.alignment.data.dist.melt.meta2$TPA_Lineage.t1=="Nichols"),])
[1] 9620
# SS14
real.correlation1.SS14 <- cor(TPA.alignment.data.dist.melt.meta2[(TPA.alignment.data.dist.melt.meta2$same.TPA.majorlineage=="same" & TPA.alignment.data.dist.melt.meta2$TPA_Lineage.t1=="SS14"),"Distance"],TPA.alignment.data.dist.melt.meta2[(TPA.alignment.data.dist.melt.meta2$same.TPA.majorlineage=="same" & TPA.alignment.data.dist.melt.meta2$TPA_Lineage.t1=="SS14"),"Geographic.Distance"])
real.correlation1.SS14
[1] 0.3091876
nrow(TPA.alignment.data.dist.melt.meta2[(TPA.alignment.data.dist.melt.meta2$same.TPA.majorlineage=="same" & TPA.alignment.data.dist.melt.meta2$TPA_Lineage.t1=="SS14"),])
[1] 181476

So looking at the full dataset

# Accross whole dataset
Correlation.gen.v.geo.dist.all.samples <- calculate.genetic.vs.geographic.distance.correlation(TPA.alignment.data.dist.melt.meta2)
Correlation.gen.v.geo.dist.all.samples[1,]

# Accross whole dataset, but constrained to genetic distances within lineage
Correlation.gen.v.geo.dist.all.samples.Lineage <- calculate.genetic.vs.geographic.distance.correlation(TPA.alignment.data.dist.melt.meta2[TPA.alignment.data.dist.melt.meta2$same.TPA.majorlineage=="same",])
Correlation.gen.v.geo.dist.all.samples.Lineage[1,]

# Explicitly By Lineage
Correlation.gen.v.geo.dist.Nichols.Lineage <- calculate.genetic.vs.geographic.distance.correlation(TPA.alignment.data.dist.melt.meta2[(TPA.alignment.data.dist.melt.meta2$same.TPA.majorlineage=="same" & TPA.alignment.data.dist.melt.meta2$TPA_Lineage.t1=="Nichols"),])
Correlation.gen.v.geo.dist.Nichols.Lineage[1,]

Correlation.gen.v.geo.dist.SS14.Lineage <- calculate.genetic.vs.geographic.distance.correlation(TPA.alignment.data.dist.melt.meta2[(TPA.alignment.data.dist.melt.meta2$same.TPA.majorlineage=="same" & TPA.alignment.data.dist.melt.meta2$TPA_Lineage.t1=="SS14"),])
Correlation.gen.v.geo.dist.SS14.Lineage[1,]


# Explicitly By sublineage

Now do it within major sublineages)

# Genetic Distance v.s. Geographic Distance (same sublineages)
TPA.alignment.data.dist.melt.meta2$TPA.pinecone.sublineage.t1 <- factor(TPA.alignment.data.dist.melt.meta2$TPA.pinecone.sublineage.t1, levels=sublineages.cols.brew$sublineage)


sublineage_names <- c(`1`="Sublineage 1",`2`="Sublineage 2",`8`="Sublineage 8",`14`="Sublineage 14")


p.geographic.vs.genetic.distance.hex.sublin <- ggplot(TPA.alignment.data.dist.melt.meta2[(TPA.alignment.data.dist.melt.meta2$same.TPA.Pinecone.cluster=="same" & TPA.alignment.data.dist.melt.meta2$TPA.pinecone.sublineage.t1 %in% c(1,2,8,14)),], aes(Geographic.Distance,Distance)) +
#ggplot(TPA.alignment.data.dist.melt.meta2, aes(Geographic.Distance,Distance)) + 
  stat_bin_hex(colour="white", na.rm=TRUE, bins = 20) +
  #geom_density_2d_filled() + scale_fill_brewer(palette="PuRd") +
  scale_fill_gradientn(colours=c("purple","green"), 
                       name = "Comparison Frequency", breaks=c(3,100,3000),
                       na.value=NA, trans="log10") + 
  theme_light() +
  scale_y_continuous(breaks=seq(0,250,10)) +
  labs(y="Pairwise genetic distance (SNPs)", x="Pairwise geographic distance (kilometers)") +
  theme.text.size + theme(legend.key.size = unit(0.75,"line")) +
  theme(strip.background = element_rect(fill='white',linetype="solid"), strip.text.x=element_text(color="grey25", size=10), strip.text.y=element_text(color="grey25", size=10)) +
  theme(legend.position="bottom") +
  #ggtitle("Pairwise SNPs (same sublineage) and Years within and between British Columbia (Canada) and England (UK)") + theme(plot.title = element_text(size = 10)) +
  facet_wrap(vars(TPA.pinecone.sublineage.t1), labeller=as_labeller(sublineage_names)) +
  stat_smooth(method='lm', fullrange=F,se=T, color='black', level=95) +
  NULL


p.geographic.vs.genetic.distance.hex.sublin 

NA
NA
NA

Combine lineage and sublineage distance plots

plot.geographic.distance.within.Lin.Sublin <- plot_grid(p.geographic.vs.genetic.distance.hex.Lineage, p.geographic.vs.genetic.distance.hex.sublin + theme(legend.position='none'), ncol=1, rel_heights=c(3,4), labels=c('A','B'), label_size=11) 


#Cairo::Cairo(file=paste0(Figure_output_directory, "Supplementary_Figure12_Genetic-vs-Geographic_distance__02-2021.svg"), width = 600, height = 600,type="svg",units = "pt")
plot.geographic.distance.within.Lin.Sublin

#dev.off()

Create Supplementary Metadata output file

#colnames(TPA.meta1.2)
TPA.meta1.2.final.Supplementary <- TPA.meta1.2[,c("Sample_Name", "Sanger_Lane_ID_raw", "Cleaned_fastq_id", "Cleaned_fastq_readcount","SRR/ENA_Accession","Reads_or_assemblies","Species","Sample_Year","Citation","Sample_Type","Clinical","Direct_from_clin","Duplicate","Geo_Region","Geo_Country","Continent","TPA_Lineage","Proportion-N_>5_mapping+masking_Nichols","Mapping_Good<25%N","Mapping_Terrible>75%N","Mean_mapping_coverage")]

# Apend info about which samples were used in the finescale clustering analysis
#colnames(TPA.meta1.2.pinecone)
TPA.meta1.2.final.Supplementary <- plyr::join(TPA.meta1.2.final.Supplementary,TPA.meta1.2.pinecone[,c("Sample_Name","TPA.pinecone.sublineage")], by="Sample_Name", type="full")
TPA.meta1.2.final.Supplementary$finescale.analysis <- ifelse(is.na(TPA.meta1.2.final.Supplementary$TPA.pinecone.sublineage),"No","Yes")

# Append info about which samples were used in the temporal BEAST analysis
in.beast.tree <- data.frame(Sample_Name=full.beast2.tipnames$meta.name,stringsAsFactors=F)
in.beast.tree$full.temporal.analysis <- "Yes"
TPA.meta1.2.final.Supplementary <- plyr::join(TPA.meta1.2.final.Supplementary, in.beast.tree, by="Sample_Name", type="full")
TPA.meta1.2.final.Supplementary$full.temporal.analysis <- ifelse(is.na(TPA.meta1.2.final.Supplementary$full.temporal.analysis),"No","Yes")

# Append antimicrobial resistance information
TPA.meta1.2.final.Supplementary <- plyr::join(TPA.meta1.2.final.Supplementary, data.frame(Sample_Name=TPA.global.compmapping.23s$Sample, A2058G=TPA.global.compmapping.23s$VariantPresent_A2058G_redo, A2059G=TPA.global.compmapping.23s$VariantPresent_A2059G_redo, stringsAsFactors=F), by="Sample_Name", type="full")

# Relabel citation for novel sequences

TPA.meta1.2.final.Supplementary[TPA.meta1.2.final.Supplementary$Citation=="unpublished-WSI","Citation"] <- "This_Study"
TPA.meta1.2.final.Supplementary[TPA.meta1.2.final.Supplementary$Citation=="unpublished-Taiaroa","Citation"] <- "This_Study"


# Reorder dataframe by Citation
TPA.meta1.2.final.Supplementary <- TPA.meta1.2.final.Supplementary[order(TPA.meta1.2.final.Supplementary$Citation,TPA.meta1.2.final.Supplementary$Sample_Name),]


#write.csv(TPA.meta1.2.final.Supplementary, file=paste0(Figure_output_directory, "Supplementary_Data1_Sample-Metadata__03-2021.csv"), row.names = F)

ENA assembly submissions (high quality assemblies - assemblies not actually used for paper, but will publish separately for the community)


#ENA.assemblies <- TPA.meta1.2[(TPA.meta1.2$`CheckM>95%_Completeness`=='yes' & TPA.meta1.2$`CheckM<5%-contamination`=='yes' & TPA.meta1.2$`contigs_<600`=='yes' & TPA.meta1.2$`Mapping_Good<25%N`=='Yes' & TPA.meta1.2$Citation=="unpublished-WSI"),c("Sample_Name", "Sanger_Lane_ID_raw", "Cleaned_fastq_id", "Cleaned_fastq_readcount","SRR/ENA_Accession","Reads_or_assemblies","Species","Sample_Year","Citation","Sample_Type","Clinical","Direct_from_clin","Duplicate","Geo_Region","Geo_Country","Continent","TPA_Lineage","Proportion-N_>5_mapping+masking_Nichols","Mapping_Good<25%N","Mapping_Terrible>75%N","Mean_mapping_coverage","SPAdes-pilon_assembly_id","Assembly_#_contigs","Assembly_N50","CheckM-completeness","CheckM-contamination")]


#ENA.assemblies <- ENA.assemblies[ENA.assemblies$`Assembly_#_contigs`<250,]
#ENA.assemblies <- ENA.assemblies[ENA.assemblies$`CheckM-contamination`<2.5,]
#ENA.assemblies <- ENA.assemblies[!is.na(ENA.assemblies$Sample_Name),]


c("NL12", "PHE120006A", "PHE120007A", "PHE120009B", "PHE120011A", "PHE120021A", "PHE120024A", "PHE130036A", "PHE130039A", "PHE130040A", "PHE130043A", "PHE130045A", "PHE130047A", "PHE130052A", "PHE130053A", "PHE130064A", "PHE140073A", "PHE140074A", "PHE140084A", "PHE140085A", "PHE140093A", "PHE140095A", "PHE150110A", "PHE150119A", "PHE150121A", "PHE150122A", "PHE150126A", "PHE150130A", "PHE150131A", "PHE150133A", "PHE150137A", "PHE150138A", "PHE150143A", "PHE150145A", "PHE150148A", "PHE150149A", "PHE150153A", "PHE150160A", "PHE150161A", "PHE150162A", "PHE150166A", "PHE150177A", "PHE160190A", "PHE160196A", "PHE160197A", "PHE160198A", "PHE160203A", "PHE160211A", "PHE160214A", "PHE160217A", "PHE160224A", "PHE160239A", "PHE160240A", "PHE160243A", "PHE160249A", "PHE160253A", "PHE160256A", "PHE160259A", "PHE160262A", "PHE160264A", "PHE160277A", "PHE160280A", "PHE160287A", "PHE160290A", "PHE160298A", "PHE160299A", "PHE160309A", "PHE160312A", "PHE160315A", "PHE160316A", "PHE170328A", "PHE170329A", "PHE170333A", "PHE170336B", "PHE170346A", "PHE170349A", "PHE170351A", "PHE170352A", "PHE170356A", "PHE170366A", "PHE170370A", "PHE170372A", "PHE170374A", "PHE170380A", "PHE170381A", "PHE170387A", "PHE170388A", "PHE170398A", "PHE170402A", "PHE170403A", "PHE170405A", "PHE170407A", "PHE170408A", "TPA_ALC015", "TPA_ALC034", "TPA_ALC077", "TPA_BCC004", "TPA_BCC005", "TPA_BCC008", "TPA_BCC009", "TPA_BCC012", "TPA_BCC014", "TPA_BCC023", "TPA_BCC030", "TPA_BCC032", "TPA_BCC034", "TPA_BCC040", "TPA_BCC049", "TPA_BCC052", "TPA_BCC055", "TPA_BCC058", "TPA_BCC061", "TPA_BCC063", "TPA_BCC064", "TPA_BCC075", "TPA_BCC079", "TPA_BCC085", "TPA_BCC088", "TPA_BCC101", "TPA_BCC102", "TPA_BCC106", "TPA_BCC108", "TPA_BCC109", "TPA_BCC111", "TPA_BCC122", "TPA_BCC127", "TPA_BCC128", "TPA_BCC129", "TPA_BCC130", "TPA_BCC132", "TPA_BCC134", "TPA_BCC137", "TPA_BCC139", "TPA_BCC140", "TPA_BCC141", "TPA_reBCC165", "TPA_BCC166", "TPA_BCC174", "TPA_BCC175", "TPA_BCC181", "TPA_BCC185", "TPA_BCC186", "TPA_BCC187", "TPA_BCC196", "TPA_BCC197", "TPA_BCC198", "TPA_BCC199", "TPA_EIR008", "TPA_EIR013", "TPA_EIR015", "TPA_EIR017", "TPA_ESBCN005", "TPA_OMI002", "TPA_OMI015", "TPA_OMI021", "TPA_OMI075", "TPA_UKBIR026", "TPA_UKBIR028", "TPA_UKBIR044", "TPA_UKBIR052", "TPA_UKBRG004", "TPA_UKBRG008", "TPA_UKBRG010", "TPA_UKBRG012", "TPA_UKBRG017", "TPA_UKBRG018", "TPA_UKLEE004", "TPA_UKMAN003", "TPA_UKMAN019", "TPA_UKMAN027", "TPA_UKMAN047", "TPA_UKMAN054", "TPA_USL-BAL-2", "TPA_USL-BAL-6", "TPA_USL-BAL-7", "TPA_USL-BAL-8", "TPA_USL-Grady-1", "TPA_USL-Haiti-B", "TPA_USL-Phil-1", "TPA_USL-Phil-3", "TPA_USL-SEA-81-3", "TPA_USL-SEA-81-8", "TPA_USL-SEA-83-1", "TPA_USL-SEA-83-2", "TPA_USL-SEA-84-2", "TPA_USL-SEA-86-1", "TPA_USL-SEA-87-1", "TPA_ZIM005", "TPA_ZIM007", "TPA_ZIM018", "TPA_ZIM024", "TPA_ZIM025", "TPA_ZIM028", "UW202B", "TPA_ALC105", "TPA_BCC103", "TPA_OMI006", "TPA_OMI022", "TPA_OMI029", "TPA_OMI033", "TPA_ZIM019", "TPA_HUN190022", "TPA_HUN200024", "TPA_HUN190020", "TPA_RUS_Tuva-39", "TPA_RUS_Tuva-58", "TPA_RUS_Tuva-59", "TPA_RUS_Tuva-26", "TPA_RUS_Tuva-41", "TPA_SWE-996", "TPA_AUSBR-41")
  [1] "NL12"             "PHE120006A"       "PHE120007A"       "PHE120009B"       "PHE120011A"       "PHE120021A"       "PHE120024A"      
  [8] "PHE130036A"       "PHE130039A"       "PHE130040A"       "PHE130043A"       "PHE130045A"       "PHE130047A"       "PHE130052A"      
 [15] "PHE130053A"       "PHE130064A"       "PHE140073A"       "PHE140074A"       "PHE140084A"       "PHE140085A"       "PHE140093A"      
 [22] "PHE140095A"       "PHE150110A"       "PHE150119A"       "PHE150121A"       "PHE150122A"       "PHE150126A"       "PHE150130A"      
 [29] "PHE150131A"       "PHE150133A"       "PHE150137A"       "PHE150138A"       "PHE150143A"       "PHE150145A"       "PHE150148A"      
 [36] "PHE150149A"       "PHE150153A"       "PHE150160A"       "PHE150161A"       "PHE150162A"       "PHE150166A"       "PHE150177A"      
 [43] "PHE160190A"       "PHE160196A"       "PHE160197A"       "PHE160198A"       "PHE160203A"       "PHE160211A"       "PHE160214A"      
 [50] "PHE160217A"       "PHE160224A"       "PHE160239A"       "PHE160240A"       "PHE160243A"       "PHE160249A"       "PHE160253A"      
 [57] "PHE160256A"       "PHE160259A"       "PHE160262A"       "PHE160264A"       "PHE160277A"       "PHE160280A"       "PHE160287A"      
 [64] "PHE160290A"       "PHE160298A"       "PHE160299A"       "PHE160309A"       "PHE160312A"       "PHE160315A"       "PHE160316A"      
 [71] "PHE170328A"       "PHE170329A"       "PHE170333A"       "PHE170336B"       "PHE170346A"       "PHE170349A"       "PHE170351A"      
 [78] "PHE170352A"       "PHE170356A"       "PHE170366A"       "PHE170370A"       "PHE170372A"       "PHE170374A"       "PHE170380A"      
 [85] "PHE170381A"       "PHE170387A"       "PHE170388A"       "PHE170398A"       "PHE170402A"       "PHE170403A"       "PHE170405A"      
 [92] "PHE170407A"       "PHE170408A"       "TPA_ALC015"       "TPA_ALC034"       "TPA_ALC077"       "TPA_BCC004"       "TPA_BCC005"      
 [99] "TPA_BCC008"       "TPA_BCC009"       "TPA_BCC012"       "TPA_BCC014"       "TPA_BCC023"       "TPA_BCC030"       "TPA_BCC032"      
[106] "TPA_BCC034"       "TPA_BCC040"       "TPA_BCC049"       "TPA_BCC052"       "TPA_BCC055"       "TPA_BCC058"       "TPA_BCC061"      
[113] "TPA_BCC063"       "TPA_BCC064"       "TPA_BCC075"       "TPA_BCC079"       "TPA_BCC085"       "TPA_BCC088"       "TPA_BCC101"      
[120] "TPA_BCC102"       "TPA_BCC106"       "TPA_BCC108"       "TPA_BCC109"       "TPA_BCC111"       "TPA_BCC122"       "TPA_BCC127"      
[127] "TPA_BCC128"       "TPA_BCC129"       "TPA_BCC130"       "TPA_BCC132"       "TPA_BCC134"       "TPA_BCC137"       "TPA_BCC139"      
[134] "TPA_BCC140"       "TPA_BCC141"       "TPA_reBCC165"     "TPA_BCC166"       "TPA_BCC174"       "TPA_BCC175"       "TPA_BCC181"      
[141] "TPA_BCC185"       "TPA_BCC186"       "TPA_BCC187"       "TPA_BCC196"       "TPA_BCC197"       "TPA_BCC198"       "TPA_BCC199"      
[148] "TPA_EIR008"       "TPA_EIR013"       "TPA_EIR015"       "TPA_EIR017"       "TPA_ESBCN005"     "TPA_OMI002"       "TPA_OMI015"      
[155] "TPA_OMI021"       "TPA_OMI075"       "TPA_UKBIR026"     "TPA_UKBIR028"     "TPA_UKBIR044"     "TPA_UKBIR052"     "TPA_UKBRG004"    
[162] "TPA_UKBRG008"     "TPA_UKBRG010"     "TPA_UKBRG012"     "TPA_UKBRG017"     "TPA_UKBRG018"     "TPA_UKLEE004"     "TPA_UKMAN003"    
[169] "TPA_UKMAN019"     "TPA_UKMAN027"     "TPA_UKMAN047"     "TPA_UKMAN054"     "TPA_USL-BAL-2"    "TPA_USL-BAL-6"    "TPA_USL-BAL-7"   
[176] "TPA_USL-BAL-8"    "TPA_USL-Grady-1"  "TPA_USL-Haiti-B"  "TPA_USL-Phil-1"   "TPA_USL-Phil-3"   "TPA_USL-SEA-81-3" "TPA_USL-SEA-81-8"
[183] "TPA_USL-SEA-83-1" "TPA_USL-SEA-83-2" "TPA_USL-SEA-84-2" "TPA_USL-SEA-86-1" "TPA_USL-SEA-87-1" "TPA_ZIM005"       "TPA_ZIM007"      
[190] "TPA_ZIM018"       "TPA_ZIM024"       "TPA_ZIM025"       "TPA_ZIM028"       "UW202B"           "TPA_ALC105"       "TPA_BCC103"      
[197] "TPA_OMI006"       "TPA_OMI022"       "TPA_OMI029"       "TPA_OMI033"       "TPA_ZIM019"       "TPA_HUN190022"    "TPA_HUN200024"   
[204] "TPA_HUN190020"    "TPA_RUS_Tuva-39"  "TPA_RUS_Tuva-58"  "TPA_RUS_Tuva-59"  "TPA_RUS_Tuva-26"  "TPA_RUS_Tuva-41"  "TPA_SWE-996"     
[211] "TPA_AUSBR-41"    
LS0tCnRpdGxlOiAiR2xvYmFsIFRQQSBVYmVyIEFuYWx5c2lzIDIwMjAvMjAyMSwgQXByaWwgMjAyMSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKQWRkIGEgbmV3IGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqSW5zZXJ0IENodW5rKiBidXR0b24gb24gdGhlIHRvb2xiYXIgb3IgYnkgcHJlc3NpbmcgKkNtZCtPcHRpb24rSSouClRyeSBleGVjdXRpbmcgdGhpcyBjaHVuayBieSBjbGlja2luZyB0aGUgKlJ1biogYnV0dG9uIHdpdGhpbiB0aGUgY2h1bmsgb3IgYnkgcGxhY2luZyB5b3VyIGN1cnNvciBpbnNpZGUgaXQgYW5kIHByZXNzaW5nICpDbWQrU2hpZnQrRW50ZXIqLiAKCgojIFJlYWQgaW4gZGVwZW5kZW5jaWVzIApgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHRyZWVpbykKbGlicmFyeShnZ3RyZWUpCmxpYnJhcnkoZ2duZXdzY2FsZSkKbGlicmFyeShwbHlyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShwaHl0b29scykKbGlicmFyeShyYW5kb21jb2xvUikKbGlicmFyeShSQ29sb3JCcmV3ZXIpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShnZ2ZvcmNlKQpsaWJyYXJ5KGdnc3RhbmNlKQpsaWJyYXJ5KGdncmlkZ2VzKQpsaWJyYXJ5KENhaXJvKQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkoZ2dtYXApCmxpYnJhcnkoQ29vcmRpbmF0ZUNsZWFuZXIpCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KGhleGJpbikKbGlicmFyeShlbW9qaWZvbnQpCmxpYnJhcnkoc2NhbGVzKQoKbGlicmFyeShwYWlyc25wKQpsaWJyYXJ5KHJQaW5lY29uZSkKClIuVmVyc2lvbigpCnByaW50KHNlc3Npb25JbmZvKCkpCmBgYAoKCiMgUmVhZCBpbiBkYXRhCmBgYHtyfQoKIyBNTCBUcmVlICh1c2luZyByYXcgc2VxdWVuY2VzIHdpdGggbWluaW1hbCBmaWx0ZXJzKQpUUEEucmF3c2VxLk1MLnRyZWUuZmlsZSA8LSAiVFBBLXViZXIucmVtYXNrZWQuMjAyMC0xMS0xMC5sb3djb3Y3NS5TTlBzLmFsbi5yZW5hbWVkLnRyZWVmaWxlIgoKIyBNTCB0cmVlIChyZWZpbmVkIGRhdGFzZXQpClRQQS5NTHRyZWUuZmlsZSA8LSAiVFBBLXViZXIucmVtYXNrZWQuMjAyMC0xMS0xMC5nb29kY292MjUuZ3ViYmlucy5TTlBzLmFsbi5yZW5hbWVkLnRyZWVmaWxlIgoKIyBQeWphciB0cmVlIChyZWZpbmVkIGRhdGFzZXQpClRQQS5weWphci5maWxlIDwtICJUUEEtdWJlci5yZW1hc2tlZC4yMDIwLTExLTEwLmdvb2Rjb3YyNS5ndWJiaW5zLlNOUHMuYWxuLnJlbmFtZWQucHlqYXIudHJlIgoKIyBNdWx0aXBsZSBTZXF1ZW5jZSBhbGlnbm1lbnQgb2YgU05QcyBmb3IgTUwgdHJlZS9weWphcgpUUEEuTVNBLlNOUHMuYWxuLmZpbGUgPC0gIlRQQS11YmVyLnJlbWFza2VkLjIwMjAtMTEtMTAuZ29vZGNvdjI1Lmd1YmJpbnMuU05Qcy5yZW5hbWVkLmFsbiIKCiMgUGluZWNvbmUgY2x1c3RlcmluZyBib290c3RyYXAgZGF0YQpwaW5lY29uZS4xMC5maWxlIDwtICJUUEEtdWJlci5ib290c3RyYXBwZWQtcGluZWNvbmUuMTAtMy4yMDIxLTAxLTI3LnYyLnBpbmVjb25lLmJvb3RzdHJhcC50YWJsZS5jc3YiCgojIE1hc3RlciBNZXRhZGF0YSBzcHJlYWRzaGVldAojVFBBLm1ldGExLmZpbGUgPC0gIi9Vc2Vycy9tYjI5L1RyZXBvbmVtYS9FeHBhbmRlZF9HbG9iYWxfU2VxdWVuY2luZy9HbG9iYWxfU2VxdWVuY2VfQ29sbGVjdGlvbl9JbmZvX3VwZGF0ZS0wMy0yMDIxLnhsc3giClRQQS5tZXRhMS5maWxlIDwtICJTdXBwbGVtZW50YXJ5X0RhdGExX1NhbXBsZS1NZXRhZGF0YV9fMDMtMjAyMS54bHN4IgoKCiMgU29tZSBwb3B1bGF0aW9uIHByZXZhbGVuY2UgZGF0YQpVSy5zdGF0cy5maWxlIDwtICJQSEVfMjAxOV9VS19TeXBoaWxpcy1yYXRlLXBlci0xMDBrLXBvcF9fMDItMTEtMjAyMC50c3YiCkJDLnN0YXRzLmZpbGUgPC0gIkJDQ0RDLUNhbmFkYV9fQkMtU3lwaGlsaXMtcmF0ZS1wZXItMTAway1wb3BfMjAxN19fXzAyLTExLTIwMjAudHN2IgoKIyBCRUFTVCBBbmFseXNlcwojIFN1YnNhbXBsZWQgQkVBU1QgYW5hbHlzaXMgMQpUUEEuYmVhc3Quc3VidHJlZS5maWxlIDwtICJUUEEtdWJlci5yZW1hc2tlZC4yMDIwLTExLTEwLmd1YmJpbnMuc3Vic2FtcGxlZC4yMDIwLTExLTE4LldHUy5yZW5kYXRlcy5ub0ludl9TdHJpY3RDU2t5bGluZV9jb21iaW5lZC4yMDIwLTExLTIzLmNvbnNlbnN1cy50cmVlIgoKYmVhc3Quc3VidHJlZS5za3lsaW5lLmZpbGUgPC0gIlRQQS11YmVyLnJlbWFza2VkLjIwMjAtMTEtMTAuZ3ViYmlucy5zdWJzYW1wbGVkLjIwMjAtMTEtMTguV0dTLnJlbmRhdGVzLm5vSW52X1N0cmljdENTa3lsaW5lXzEuZXhwb3J0X3NreWxpbmVfZGF0YS50eHQiCgpiZWFzdC5zdWJ0cmVlLnNreWxpbmUubGluZWFnZS5maWxlIDwtICJUUEEtdWJlcl9iZWFzdDJfc3RyaWN0LXNreWxpbmUtNTAwTV8xMHBvcF9jb21iaW5lZC5saW5lYWdlcy1kYXRhLnRzdiIKCgojIFN1YnNhbXBsZWQgQkVBU1QgYW5hbHlzaXMgMiAocmVwZWF0KQpyZXBlYXQuc3Vic2FtcGxlZC5za3lsaW5lLnRyZWUuZmlsZSA8LSAiVFBBLXViZXIucmVtYXNrZWQuMjAyMC0xMS0xMC5ndWJiaW5zLnN1YnNhbXBsZWQuMi4yMDIwLTExLTIzLldHUy5yZW5kYXRlcy5ub0ludi5TdHJpY3QtU2t5bGluZS1IS1lfY29tYmluZWQuMjAyMC0xMS0yNi5jb25zZW5zdXMudHJlZSIKCnJlcGVhdC5zdWJzYW1wbGVkLnNreWxpbmUuZGF0YS5maWxlIDwtICJUUEEtdWJlci5yZW1hc2tlZC4yMDIwLTExLTEwLmd1YmJpbnMuc3Vic2FtcGxlZC4yLjIwMjAtMTEtMjMuV0dTLnJlbmRhdGVzLm5vSW52LlN0cmljdC1Ta3lsaW5lLUhLWV8xLnNreWxpbmUtZGF0YS50c3YiCnJlcGVhdC5zdWJzYW1wbGVkLnNreWxpbmUubGluZWFnZXMuZGF0YS5maWxlIDwtICJUUEEtdWJlci5yZW1hc2tlZC4yMDIwLTExLTEwLmd1YmJpbnMuc3Vic2FtcGxlZC4yLjIwMjAtMTEtMjMuV0dTLnJlbmRhdGVzLm5vSW52LlN0cmljdC1Ta3lsaW5lLUhLWV8xLnNreWxpbmUtbGluZWFnZXMtZGF0YS50c3YiCgojIEZ1bGwgc2l6ZSBCRUFTVDIgYW5hbHlzaXMKZnVsbC5iZWFzdDIudHJlZS5maWxlIDwtICJUUEEtdWJlcl9iZWFzdDJfc3RyaWN0LXNreWxpbmUtNTAwTV8xMHBvcF9jb25zZW5zdXMudHJlZSIKCmJlYXN0Mi5ydW5zLmZpbGVwYXRoIDwtICIuLyIKCmJlYXN0Mi5mdWxsLnNreWxpbmUucGF0aCA8LSAiVFBBLXViZXJfYmVhc3QyX3N0cmljdC1za3lsaW5lLTUwME1fMTBwb3BfY29tYmluZWQuc2t5bGluZS1kYXRhLnRzdiIKYmVhc3QyLmZ1bGwubGluZWFnZXMucGF0aCA8LSAiVFBBLXViZXJfYmVhc3QyX3N0cmljdC1za3lsaW5lLTUwME1fMTBwb3BfY29tYmluZWQubGluZWFnZXMtZGF0YS50c3YiCmJlYXN0Mi5mdWxsLnBvcGRpc3Ryby5wYXRoIDwtICJUUEEtdWJlcl9iZWFzdDJfc3RyaWN0LXNreWxpbmUtNTAwTV8xMHBvcF9jb21iaW5lZC5wb3AtZGlzdHJpYnV0aW9uc19wMTAwLnR4dCIKCgpiZWFzdDIucG9wLmRlY2xpbmUuZmlsZSA8LSAiVFBBLXViZXJfYmVhc3QyX3N0cmljdC1za3lsaW5lLTUwME1fMTBwb3BfcG9wLWRlY2xpbmUuMTk5MC0yMDE1LnA1MF9wb3B1bGF0aW9uX2NoYW5nZV9kaXN0cmlidXRpb24uY3N2IgoKCmJlYXN0Mi5wb3AuaW5jcmVhc2UuZmlsZSAgPC0gIlRQQS11YmVyX2JlYXN0Ml9zdHJpY3Qtc2t5bGluZS01MDBNXzEwcG9wX3BvcC1pbmNyZWFzZS4xOTkwLTIwMTUucDEwMF9wb3B1bGF0aW9uX2NoYW5nZV9kaXN0cmlidXRpb24uY3N2IgoKcG9wLmRlY2xpbmUuc3VwcG9ydGluZy50cmVlcy5maWxlIDwtICJUUEEtdWJlcl9iZWFzdDJfc3RyaWN0LXNreWxpbmUtNTAwTV8xMHBvcF9wb3AtZGVjbGluZS4xOTkwLTIwMTUucDUwX3RyZWVzX3N1cHBvcnRpbmcubmV4IgoKcG9wLmRlY2xpbmUubm90c3VwcG9ydGluZy50cmVlcy5maWxlIDwtICJUUEEtdWJlcl9iZWFzdDJfc3RyaWN0LXNreWxpbmUtNTAwTV8xMHBvcF9wb3AtZGVjbGluZS4xOTkwLTIwMTUucDUwX3RyZWVzX25vdF9zdXBwb3J0aW5nLm5leCIKCgojIFN1YmxpbmVhZ2UgQkVBU1QgYW5hbHlzaXMKc3VibGluZWFnZS5za3lsaW5lcy5maWxlcGF0aCA8LSAiLi8iCnBvcC5kaXN0cm8ucGF0aCA8LSAiLi8iIApwb3AuZGlzdHJvLnN1Ymxpbi4xLmZpbGUgPC0gIlRQQS11YmVyLnJlbWFza2VkLjIwMjAtMTEtMTAuZ29vZGNvdjI1Lmd1YmJpbnMuV0dTLnN1YmxpbmVhZ2UubmV3LjEubm9pbnYuU3RyaWN0LVNreWxpbmVfY29tYmluZWQucG9wLWV4cGFuc2lvbiIKcG9wLmRpc3Ryby5zdWJsaW4uMi5maWxlIDwtICJUUEEtdWJlci5yZW1hc2tlZC4yMDIwLTExLTEwLmdvb2Rjb3YyNS5ndWJiaW5zLldHUy5zdWJsaW5lYWdlLm5ldy4yLm5vaW52LlN0cmljdC1Ta3lsaW5lX2NvbWJpbmVkLnBvcC1leHBhbnNpb24iCnBvcC5kaXN0cm8uc3VibGluLjguZmlsZSA8LSAiVFBBLXViZXIucmVtYXNrZWQuMjAyMC0xMS0xMC5nb29kY292MjUuZ3ViYmlucy5XR1Muc3VibGluZWFnZS5uZXcuOC5ub2ludi5TdHJpY3QtU2t5bGluZV9jb21iaW5lZC5wb3AtZXhwYW5zaW9uIgoKIyBSZWNvbWJpbmF0aW9uIGFuYWx5c2lzCnJlY29tYmluYXRpb25fZXZlbnQuZmlsZSA8LSAiU3VwcGxlbWVudGFyeV9UYWJsZV9SZWNvbWJpbmF0aW9uLUV2ZW50c18yMDIxLTAzLTI1Lnhsc3giCgojIFRpcCBEYXRlIFJhbmRvbWlzYXRpb24KcmFuZG9tLnRpcC5zdW1tYXJ5LmZpbGUgPC0gImNsb2NrUmF0ZS5zdGF0cy5jc3YiCgojIE1hY3JvbGlkZSByZXNpc3RhbmNlIGFsbGVsZSBjYWxscwpUUEEuZ2xvYmFsLmNvbXBtYXBwaW5nLjIzcy5maWxlIDwtImNvbXBldGl0aXZlLW1hcHBpbmdfY29tYmluZWQtcmVwb3J0cy5hbGwuMjAyMC0xMi0wMS5maW5hbC50c3YiCgojIFBpbmVjb25lIGFzc2lnbm1lbnRzCnBpbmVjb25lLmNsdXN0ZXJzLk1Mb3JpZ2luYWwuZmlsZSA8LSAiR2xvYmFsLVRQQS5nb29kY292LnJQaW5lY29uZTEwLTMuYXNzaWdubWVudHNfMjAyMC0xMS0xMS5jc3YiCgpXR1Muc2l0ZS5wb3NpdGlvbnMuZmlsZSA8LSAiVFBBLXViZXIucmVtYXNrZWQuMjAyMC0xMS0xMC5nb29kY292MjUuZ3ViYmlucy5TTlBzLnNpdGUtcG9zaXRpb25zLnR4dCIKCiMgTG9jYXRpb24gdG8gc2F2ZSBmaWxlcyB0bwpGaWd1cmVfb3V0cHV0X2RpcmVjdG9yeSA8LSAiL1VzZXJzL21iMjkvUGFwZXJzL0dsb2JhbF9UcmVwb25lbWFfVWJlci1QYXBlcl8yMDIwL0ZpZ3VyZXMvRmlndXJlX0RyYWZ0aW5nLyIKYGBgCgoKIyBSZWFkIGluIHRyZWVzCmBgYHtyfQpUUEEucmF3c2VxLk1MLnRyZWUgPC0gbWlkcG9pbnQucm9vdChyZWFkLnRyZWUoVFBBLnJhd3NlcS5NTC50cmVlLmZpbGUpKQpUUEEuTUx0cmVlIDwtIG1pZHBvaW50LnJvb3QocmVhZC50cmVlKFRQQS5NTHRyZWUuZmlsZSkpClRQQS5weWphci50cmVlIDwtIG1pZHBvaW50LnJvb3QocmVhZC50cmVlKFRQQS5weWphci5maWxlKSkKCgoKYGBgCgoKIyBtYWtlIHNvbWUgc2hvcnRjdXRzIGZvciBwbG90dGluZyAKYGBge3J9CnkudGhlbWUuc3RyaXAgPC0gdGhlbWUoYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy55PSBlbGVtZW50X2JsYW5rKCkpCnkudGhlbWUuc3RyaXAucGFydGlhbCA8LSB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy55PSBlbGVtZW50X2JsYW5rKCkpCgp4LnRoZW1lLnN0cmlwIDwtIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueD0gZWxlbWVudF9ibGFuaygpKQp4LnRoZW1lLnN0cmlwLnBhcnRpYWwgPC0gdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueD0gZWxlbWVudF9ibGFuaygpKQp4LnRoZW1lLnN0cmlwLmxhYnMgPC0gdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKQoKeC50aGVtZS5heGlzLnJvdGF0ZSA8LSB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSkpCgp0aGVtZS50ZXh0LnNpemUgPC0gdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKQoKJyVub3RpbiUnIDwtIE5lZ2F0ZSgnJWluJScpCgpgYGAKCgojIEZpbHRlciBtZXRhZGF0YQpgYGB7cn0KIyBGaXJzdCBkbyBzb21lIGNsZWFuaW5nCiNUUEEubWV0YTEgPC0gcmVhZHhsOjpyZWFkX2V4Y2VsKFRQQS5tZXRhMS5maWxlLHNoZWV0PSJBbGxfdXNlYWJsZV9ULnBhbF8wMS0yMDIwX3JlZmlsIikKVFBBLm1ldGExIDwtIHJlYWR4bDo6cmVhZF9leGNlbChUUEEubWV0YTEuZmlsZSxzaGVldD0iU3VwcGxlbWVudGFyeV9EYXRhMV9TYW1wbGUtTWV0YSIpClRQQS5tZXRhMSA8LSBzdWJzZXQoVFBBLm1ldGExLCBzZWxlY3Q9LWMoQTIwNThHLEEyMDU5RyxUUEEucGluZWNvbmUuc3VibGluZWFnZSkpCgoKVFBBLm1ldGExLjIgPC0gVFBBLm1ldGExW1RQQS5tZXRhMSRTYW1wbGVfTmFtZSAlaW4lIFRQQS5yYXdzZXEuTUwudHJlZSR0aXAubGFiZWwsXQoKVFBBLm1ldGExLjIgPC0gVFBBLm1ldGExLjJbVFBBLm1ldGExLjIkU3BlY2llcz09IlRQQSIsXQojVFBBLm1ldGExLjIgPC0gVFBBLm1ldGExLjJbVFBBLm1ldGExLjIkU3R1ZHlfVHlwZT09IlRQQS1HbG9iYWwiLF0KVFBBLm1ldGExLjIgPC0gVFBBLm1ldGExLjJbVFBBLm1ldGExLjIkRHVwbGljYXRlIT0iWWVzIixdCiNUUEEubWV0YTEuMiA8LSBUUEEubWV0YTEuMltUUEEubWV0YTEuMiRTYW1wbGVfWWVhciE9Ii0iLF0KCgojVFBBLm1ldGExLjIgPC0gVFBBLm1ldGExLjJbVFBBLm1ldGExLjIkYFNLQV9BbGlnbm1lbnRfdGVycmlibGU+NTAlP2A9PSJObyIsXQpUUEEubWV0YTEuMiA8LSBUUEEubWV0YTEuMlshaXMubmEoVFBBLm1ldGExLjIkU2FtcGxlX05hbWUpLF0KI1RQQS5tZXRhMS4yIDwtIGRhdGEuZnJhbWUoVFBBLm1ldGExLjIsc3RyaW5nc0FzRmFjdG9ycyA9IEYpCgoKVFBBLm1ldGExLjIkR2VvX0NvdW50cnkgPC0gZ3N1YigiXFxfIiwiXFwgIixUUEEubWV0YTEuMiRHZW9fQ291bnRyeSkKYGBgCgoKZG8gc29tZSBkYXRlIHBhcnNpbmcgdG8gY3JlYXRlIGRhdGUgZ3JvdXBzCmBgYHtyfQpmbG9vcl81eWVhcnMgIDwtIGZ1bmN0aW9uKHZhbHVlKXsgcmV0dXJuKHZhbHVlIC0gdmFsdWUgJSUgNSkgfQpjZWlsaW5nXzV5ZWFycyA8LSBmdW5jdGlvbih2YWx1ZSl7IHJldHVybihyb3VuZF90b181eWVhcnModmFsdWUpKzUpIH0Kcm91bmRfdG9fNXllYXJzIDwtIGZ1bmN0aW9uKHZhbHVlKXsgcmV0dXJuKHJvdW5kKHZhbHVlIC8gNSkgKiA1KSB9CgpUUEEubWV0YTEuMiRTYW1wbGVfNXllYXIuZmxvb3IgPC0gZmxvb3JfNXllYXJzKGFzLm51bWVyaWMoVFBBLm1ldGExLjIkU2FtcGxlX1llYXIpKQpUUEEubWV0YTEuMiRTYW1wbGVfNXllYXIud2luZG93IDwtIHBhc3RlMChmbG9vcl81eWVhcnMoYXMubnVtZXJpYyhUUEEubWV0YTEuMiRTYW1wbGVfWWVhcikpLCItIixmbG9vcl81eWVhcnMoYXMubnVtZXJpYyhUUEEubWV0YTEuMiRTYW1wbGVfWWVhcikpKzUpCgoKIyBTb21lIHNhbXBsZXMgaGF2ZSB1bmNlcnRhaW4gZGF0ZXMgKHVwIHRvIDIwLTMwIHllYXJzIHVuY2VydGFpbnR5KSwgYnV0IGZvciB0aGUgcHVycG9zZXMgb2YgdGhlc2UgcGxvdHRpbmcgY2F0ZWdvcmllcyB3ZSdsbCB1c2UgdGhlIGNlbnRyZXBvaW50IHllYXIKVFBBLm1ldGExLjIkU2FtcGxlXzV5ZWFyLndpbmRvdyA8LSBzYXBwbHkoMTpucm93KFRQQS5tZXRhMS4yKSwgZnVuY3Rpb24oeCkgaWZlbHNlKFRQQS5tZXRhMS4yJFNhbXBsZV9ZZWFyW3hdPT0iLSIsTkEsIGlmZWxzZShpcy5uYShUUEEubWV0YTEuMiRTYW1wbGVfNXllYXIud2luZG93W3hdKSxOQSwgaWZlbHNlKFRQQS5tZXRhMS4yJFNhbXBsZV9ZZWFyW3hdPT0iMTk1MC0xOTgwIiwiMTk2NS0xOTcwIixpZmVsc2UoVFBBLm1ldGExLjIkU2FtcGxlX1llYXJbeF09PSIxOTYwLTE5ODAiLCIxOTY1LTE5NzAiICxpZmVsc2UoVFBBLm1ldGExLjIkU2FtcGxlX1llYXJbeF09PSIxOTgwLTE5OTkiLCIxOTg1LTE5OTAiLFRQQS5tZXRhMS4yJFNhbXBsZV81eWVhci53aW5kb3dbeF0pKSkpKSkKCiNUUEEubWV0YTEuMltUUEEubWV0YTEuMiRTYW1wbGVfNXllYXIud2luZG93PT0iTkEtTkEiLCJTYW1wbGVfNXllYXIud2luZG93Il0gPC0gTkEKCiNWaWV3KFRQQS5tZXRhMS4yWyxjKCJTYW1wbGVfTmFtZSIsIlNhbXBsZV9ZZWFyIiwiU2FtcGxlXzV5ZWFyLndpbmRvdyIpXSkKCgojIE1ha2UgY29sb3VyIHNjaGVtZSBmb3IgZGF0ZSB3aW5kb3cKVFBBLjV5ZWFyLndpbmRvdy5icmV3Y29scyA8LSBkYXRhLmZyYW1lKHdpbmRvdy41eWVhcj11bmlxdWUoVFBBLm1ldGExLjIkU2FtcGxlXzV5ZWFyLndpbmRvdyksIHN0cmluZ3NBc0ZhY3RvcnM9RikKVFBBLjV5ZWFyLndpbmRvdy5icmV3Y29scyR3aW5kb3cuNXllYXIgPC0gVFBBLjV5ZWFyLndpbmRvdy5icmV3Y29sc1tvcmRlcihUUEEuNXllYXIud2luZG93LmJyZXdjb2xzJHdpbmRvdy41eWVhciksXQpUUEEuNXllYXIud2luZG93LmJyZXdjb2xzJHdpbmRvdy41eWVhciA8LSBmYWN0b3IoVFBBLjV5ZWFyLndpbmRvdy5icmV3Y29scyR3aW5kb3cuNXllYXIsIGxldmVscz1UUEEuNXllYXIud2luZG93LmJyZXdjb2xzJHdpbmRvdy41eWVhcikKIyBzZXQgY29sb3VyIHNjYWxlClRQQS41eWVhci53aW5kb3cuYnJld2NvbHMkd2luZG93LjV5ZWFyLmNvbHMgPC0gYygiQmxhY2siLGJyZXdlci5wYWwobj0xMSwiUmRZbEJ1IiksIndoaXRlIikKCiNjKCIxOTEwLTE5MTUiLCIxOTUwLTE5NTUiLCIxOTY1LTE5NzAsIjE5NzAtMTk3NSIsIjE5NzUtMTk4MCIsIjE5ODAtMTk4NSIsIjE5ODUtMTk5MCIsIjE5OTAtMTk5NSIsIjIwMDAtMjAwNSIsIjIwMDUtMjAxMCIsIjIwMTAtMjAxNSIsIjIwMTUtMjAyMCIsIk5BIikKCgojIEFsc28gY3JlYXRlIGEgbnVtZXJpYyBkYXRlIHllYXIgZm9yIHNvbWUgY2FsY3VsYXRpb25zClRQQS5tZXRhMS4yJFNhbXBsZV9ZZWFyLm51bSA8LSBhcy5udW1lcmljKChpZmVsc2UoVFBBLm1ldGExLjIkU2FtcGxlX1llYXI9PSIxOTUwLTE5ODAiLCIxOTY1IixpZmVsc2UoVFBBLm1ldGExLjIkU2FtcGxlX1llYXI9PSIxOTYwLTE5ODAiLCIxOTcwIixUUEEubWV0YTEuMiRTYW1wbGVfWWVhcikpKSkKCmBgYAoKQ3JlYXRlIGEgY29sb3VyIHNjaGVtZSBmb3IgY291bnRyaWVzIGFuZCBjb250aW5lbnRzCmBgYHtyfQojIENvbG91cmluZyBmb3IgY291bnRyeQpjb250aW5lbnRhbC5jb3VudHJ5LmNvbHMuYnJldzIgPC0gdW5pcXVlKFRQQS5tZXRhMS4yWyxjKCJHZW9fQ291bnRyeSIsIkNvbnRpbmVudCIpXSkKY29udGluZW50YWwuY291bnRyeS5jb2xzLmJyZXcyIDwtIGNvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MltvcmRlcihjb250aW5lbnRhbC5jb3VudHJ5LmNvbHMuYnJldzIkQ29udGluZW50LGNvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MiRHZW9fQ291bnRyeSksXQoKY29udGluZW50YWwuY291bnRyeS5jb2xzLmJyZXcyJGNvdW50cnkuY29sIDwtIGMoIiNlYzcwMTQiLCIjZmVjNDRmIiwiI2RlMmQyNiIsIiNmYjZhNGEiLCIjYmRiZGJkIiwiIzczNzM3MyIsYnJld2VyLnBhbChuPTgsIlB1cnBsZXMiKVszOjhdLGJyZXdlci5wYWwobj04LCJCbHVlcyIpWzM6OF0sYnJld2VyLnBhbChuPTUsIkdyZWVucyIpWzM6NV0sIiNjNTFiOGEiLCIjOGM1MTBhIikKCiMgQ29sb3VyaW5nIGZvciBDb250aW5lbnQKY29udGluZW50YWwuY29scy5icmV3MiA8LSBkYXRhLmZyYW1lKENvbnRpbmVudD1zb3J0KHVuaXF1ZShUUEEubWV0YTEuMiRDb250aW5lbnQpKSxzdHJpbmdzQXNGYWN0b3JzPUYpCmNvbnRpbmVudGFsLmNvbHMuYnJldzIkY29udGluZW50LmNvbCA8LSBjKCIjZmVjNDRmIiwiI2RlMmQyNiIsIiNiZGJkYmQiLCIjMjE3MWI1IiwiIzc0YzQ3NiIsIiNjNTFiOGEiLCIjZWM3MDE0IikKCiMgQ29sb3VyaW5nIGZvciBUUEEgTGluZWFnZQpUUEFfTGluZWFnZS5jb2xzIDwtIGRhdGEuZnJhbWUoTGluZWFnZT1zb3J0KHVuaXF1ZShUUEEubWV0YTEuMiRUUEFfTGluZWFnZSkpLHN0cmluZ3NBc0ZhY3RvcnM9RikKI1RQQV9MaW5lYWdlLmNvbHMkTGluZWFnZS5jb2wgPC0gYygicm95YWxibHVlMiIsICJncmV5NDAiLCAiaW5kaWFucmVkMSIpClRQQV9MaW5lYWdlLmNvbHMkTGluZWFnZS5jb2wgPC0gYygicm95YWxibHVlMiIsICJpbmRpYW5yZWQxIikKI2MoIiM0MzZlZWUiLCAiIzY2NjY2NiIsIiNmZjZhNmEiKQpUUEFfTGluZWFnZS5jb2xzJExpbmVhZ2UgPC0gZmFjdG9yKFRQQV9MaW5lYWdlLmNvbHMkTGluZWFnZSwgbGV2ZWxzPWMoIk5pY2hvbHMiLCJTUzE0Iiwib3V0bGllciIpKQojVFBBX0xpbmVhZ2UuY29scyRMaW5lYWdlIDwtIGZhY3RvcihUUEFfTGluZWFnZS5jb2xzJExpbmVhZ2UsIGxldmVscz1jKCJOaWNob2xzIiwiU1MxNCIpKQoKCiMgTGluZWFnZSBIZXhjb2RlcwojIHJveWFsYmx1ZTIgIzQzNmVlZQojIGluZGlhbnJlZDEgI2ZmNmE2YQoKCiNUUEFfTGluZWFnZS5jb2xzW29yZGVyKFRQQV9MaW5lYWdlLmNvbHMkTGluZWFnZSxjKCJOaWNob2xzIiwiU1MxNCIsIm91dGxpZXIiKSksXQpgYGAKCiMgY2hlY2sgbGFiZWxsaW5nIGlzc3VlcwpgYGB7cn0KVFBBLnJhd3NlcS5NTC50cmVlJHRpcC5sYWJlbFtUUEEucmF3c2VxLk1MLnRyZWUkdGlwLmxhYmVsICVub3RpbiUgVFBBLm1ldGExLjIkU2FtcGxlX05hbWVdCgpUUEEubWV0YTEuMiRTYW1wbGVfTmFtZVtUUEEubWV0YTEuMiRTYW1wbGVfTmFtZSAlbm90aW4lIFRQQS5yYXdzZXEuTUwudHJlZSR0aXAubGFiZWxdCmBgYAoKYGBge3J9CiMgVGhlcmUgaXMgb25lIHZlcnkgbG93IGNvdmVyYWdlIHNhbXBsZSAoVFBBX0JDQzE0NCwgNDclIGdlbm9tZSBicmVhZHRoLCA3LjlYIG1lYW4gY292ZXJhZ2UpIHdpdGggb2RkIHBoeWxvZ2VuZXRpYyBwbGFjZW1lbnQgLSBpdCdzIFNTMTQsIGJ1dCBiYXNhbCBpbiB0aGlzIGFuYWx5c2lzLiBTaW5jZSB0aGUgY292ZXJhZ2UgaXMgc28gbG93LCBpdCdzIG5vdCBwb3NzaWJsZSB0byBmdXJ0aGVyIGludmVzdGlnYXRlIHRoaXMsIHNvIGNsYXNzaWZ5IGl0IGhlcmUgYXMgU1MxNC4KVFBBLm1ldGExLjJbKFRQQS5tZXRhMS4yJFRQQV9MaW5lYWdlPT0ib3V0bGllciIpLCJUUEFfTGluZWFnZSJdIDwtICJTUzE0IgpgYGAKCgoKCmBgYHtyfQojIFByZXBhcmUgdHJlZQpUUEEucmF3c2VxLk1MLmdndHJlZSA8LSBnZ3RyZWUoVFBBLnJhd3NlcS5NTC50cmVlLGxheW91dCA9ICJmYW4iLG9wZW4uYW5nbGUgPSAyMCwgcmlnaHQ9VCkKVFBBLnJhd3NlcS5NTC5nZ3RyZWUgPC0gZ2d0cmVlKFRQQS5yYXdzZXEuTUwudHJlZSxsYXlvdXQgPSAiZmFuIixvcGVuLmFuZ2xlID0gMTUsIHJpZ2h0PVQpCgojIFByZXBhcmUgY291bnRyeSBkYXRhc2V0ClRQQS5yYXdzZXEuY291bnRyaWVzLnAgPC0gZGF0YS5mcmFtZShyb3cubmFtZXM9VFBBLm1ldGExLjIkU2FtcGxlX05hbWUsIENvdW50cnk9VFBBLm1ldGExLjIkR2VvX0NvdW50cnksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQoKIyBQcmVwYXJlIGNvbnRpbmVudCBkYXRhc2V0ClRQQS5yYXdzZXEuY29udGluZW50cy5wIDwtIGRhdGEuZnJhbWUocm93Lm5hbWVzPVRQQS5tZXRhMS4yJFNhbXBsZV9OYW1lLCBDb250aW5lbnQ9VFBBLm1ldGExLjIkQ29udGluZW50LCBzdHJpbmdzQXNGYWN0b3JzID0gRikKCiMgUHJlcGFyZSBNYWpvciBsaW5lYWdlIGRhdGFzZXQKVFBBLnJhd3NlcS5MaW5lYWdlLnAgPC0gZGF0YS5mcmFtZShyb3cubmFtZXM9VFBBLm1ldGExLjIkU2FtcGxlX05hbWUsIExpbmVhZ2U9VFBBLm1ldGExLjIkVFBBX0xpbmVhZ2UsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQpgYGAKCmBgYHtyfQpUUEEucmF3c2VxLk1MLmdndHJlZS50aXBwb2ludHMgPC0gVFBBLnJhd3NlcS5NTC5nZ3RyZWUgJTwrJSBkYXRhLmZyYW1lKFNhbXBsZV9OYW1lPXJvd25hbWVzKFRQQS5yYXdzZXEuY29udGluZW50cy5wKSwgQ29udGluZW50PVRQQS5yYXdzZXEuY29udGluZW50cy5wJENvbnRpbmVudCwgc3RyaW5nc0FzRmFjdG9ycyA9IEYpICsgCiAgZ2VvbV90aXBwb2ludChhZXMoY29sb3I9Q29udGluZW50KSwgc2l6ZT0wLjUsIGFscGhhPTAuNSkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZT0iQ29udGluZW50Iix2YWx1ZXM9Y29udGluZW50YWwuY29scy5icmV3MiRjb250aW5lbnQuY29sLCBicmVha3M9Y29udGluZW50YWwuY29scy5icmV3MiRDb250aW5lbnQpIAoKIyBSZXNjYWxlIGNvbG91cnMKVFBBLnJhd3NlcS5NTC5nZ3RyZWUudGlwcG9pbnRzIDwtIFRQQS5yYXdzZXEuTUwuZ2d0cmVlLnRpcHBvaW50cyArIG5ld19zY2FsZV9jb2xvcigpCgojIFBsb3QgY29udGluZW50IHN0cmlwCnAuVFBBLnJhd3NlcS5NTC5nZ3RyZWUudGlwcG9pbnQuY291bnRyeS5jb250IDwtIGdoZWF0bWFwKFRQQS5yYXdzZXEuTUwuZ2d0cmVlLnRpcHBvaW50cyxUUEEucmF3c2VxLmNvbnRpbmVudHMucCwgY29sb3I9TlVMTCx3aWR0aD0wLjA3NSxjb2xuYW1lc19hbmdsZT0tNDUsY29sbmFtZXNfb2Zmc2V0X3k9MC4wMiwgaGp1c3Q9MC4wLGZvbnQuc2l6ZT0yLjI1KSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWU9IkNvbnRpbmVudCIsdmFsdWVzPWNvbnRpbmVudGFsLmNvbHMuYnJldzIkY29udGluZW50LmNvbCwgYnJlYWtzPWNvbnRpbmVudGFsLmNvbHMuYnJldzIkQ29udGluZW50KSArIAogIHRoZW1lLnRleHQuc2l6ZSArIHRoZW1lKGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC42NSwibGluZSIpLGxlZ2VuZC5wb3NpdGlvbj0ncmlnaHQnKSArCiAgTlVMTApwLlRQQS5yYXdzZXEuTUwuZ2d0cmVlLnRpcHBvaW50LmNvdW50cnkuY29udCA8LSBwLlRQQS5yYXdzZXEuTUwuZ2d0cmVlLnRpcHBvaW50LmNvdW50cnkuY29udCArIG5ld19zY2FsZV9maWxsKCkKCgoKcC5UUEEucmF3c2VxLk1MLmdndHJlZS50aXBwb2ludC5jb3VudHJ5LmNvbnQgPC0gZ2hlYXRtYXAocC5UUEEucmF3c2VxLk1MLmdndHJlZS50aXBwb2ludC5jb3VudHJ5LmNvbnQsVFBBLnJhd3NlcS5jb3VudHJpZXMucCwgY29sb3I9TlVMTCx3aWR0aD0wLjA3NSxvZmZzZXQ9MC4wMDAwMTIyNSwgY29sbmFtZXNfYW5nbGU9LTQ1LGNvbG5hbWVzX29mZnNldF95PTAuMDIsIGhqdXN0PTAuMCxmb250LnNpemU9Mi4yNSkgKyAKICBzY2FsZV9maWxsX21hbnVhbChuYW1lPSJDb3VudHJ5Iix2YWx1ZXM9Y29udGluZW50YWwuY291bnRyeS5jb2xzLmJyZXcyJGNvdW50cnkuY29sLCBicmVha3M9Y29udGluZW50YWwuY291bnRyeS5jb2xzLmJyZXcyJEdlb19Db3VudHJ5KSArCiAgdGhlbWUudGV4dC5zaXplICsgdGhlbWUobGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjY1LCJsaW5lIiksbGVnZW5kLnBvc2l0aW9uPSdyaWdodCcpICsKICBOVUxMCnAuVFBBLnJhd3NlcS5NTC5nZ3RyZWUudGlwcG9pbnQuY291bnRyeS5jb250IDwtIHAuVFBBLnJhd3NlcS5NTC5nZ3RyZWUudGlwcG9pbnQuY291bnRyeS5jb250ICsgbmV3X3NjYWxlX2ZpbGwoKQoKCiMgQWRkIHN1YmxpbmVhZ2UKcC5UUEEucmF3c2VxLk1MLmdndHJlZS50aXBwb2ludC5jb3VudHJ5LmNvbnQgPC0gZ2hlYXRtYXAocC5UUEEucmF3c2VxLk1MLmdndHJlZS50aXBwb2ludC5jb3VudHJ5LmNvbnQsVFBBLnJhd3NlcS5MaW5lYWdlLnAsIGNvbG9yPU5VTEwsd2lkdGg9MC4wNzUsb2Zmc2V0PTAuMDAwMDI0MjUsIGNvbG5hbWVzX2FuZ2xlPS00NSxjb2xuYW1lc19vZmZzZXRfeT0wLjAyLCBoanVzdD0tMC4wLGZvbnQuc2l6ZT0yLjI1KSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWU9IkxpbmVhZ2UiLHZhbHVlcz1UUEFfTGluZWFnZS5jb2xzJExpbmVhZ2UuY29sLCBicmVha3M9VFBBX0xpbmVhZ2UuY29scyRMaW5lYWdlKSArCiAgdGhlbWUudGV4dC5zaXplICsgdGhlbWUobGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjY1LCJsaW5lIiksbGVnZW5kLnBvc2l0aW9uPSdyaWdodCcpICsKICBOVUxMCnAuVFBBLnJhd3NlcS5NTC5nZ3RyZWUudGlwcG9pbnQuY291bnRyeS5jb250IDwtIHAuVFBBLnJhd3NlcS5NTC5nZ3RyZWUudGlwcG9pbnQuY291bnRyeS5jb250ICsgbmV3X3NjYWxlX2ZpbGwoKQoKIyBQbG90IHRyZWUKI3AuVFBBLnJhd3NlcS5NTC5nZ3RyZWUudGlwcG9pbnQuY291bnRyeS5jb250CmBgYApgYGB7cn0KCiNDYWlybzo6Q2Fpcm8oZmlsZT1wYXN0ZTAoRmlndXJlX291dHB1dF9kaXJlY3RvcnksICJTdXBwbGVtZW50YXJ5X0ZpZ3VyZTFfR2xvYmFsLVRQQS5sb3ctY292LU1MdHJlZV8wMi0yMC5zdmciKSwgd2lkdGggPSAxMDAwLCBoZWlnaHQgPSAxMDAwLHR5cGU9InN2ZyIsdW5pdHMgPSAicHQiKQpwLlRQQS5yYXdzZXEuTUwuZ2d0cmVlLnRpcHBvaW50LmNvdW50cnkuY29udAojZGV2Lm9mZigpCmBgYAoKCgpgYGB7ciwgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9MywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KVFBBLnJhd3NlcS5jb3VudHJ5LmNvdW50cyA8LSBUUEEubWV0YTEuMltUUEEubWV0YTEuMiRTYW1wbGVfWWVhciE9Ii0iLF0gJT4lIGRwbHlyOjpncm91cF9ieShTYW1wbGVfWWVhciwgR2VvX0NvdW50cnkpICU+JSAKICBkcGx5cjo6c3VtbWFyaXNlKENvdW50PW4oKSkKClRQQS5yYXdzZXEuY291bnRyeS5jb3VudHMkU2FtcGxlX1llYXIgPC0gaWZlbHNlKFRQQS5yYXdzZXEuY291bnRyeS5jb3VudHMkU2FtcGxlX1llYXI9PSIxOTYwLTE5ODAiLCIxOTcwIixUUEEucmF3c2VxLmNvdW50cnkuY291bnRzJFNhbXBsZV9ZZWFyKQoKVFBBLnJhd3NlcS5jb3VudHJ5LmNvdW50cyA8LSBwbHlyOjpqb2luKGRhdGEuZnJhbWUoU2FtcGxlX1llYXI9YygxOTEyOjIwMTkpLHN0cmluZ3NBc0ZhY3RvcnM9RiksIFRQQS5yYXdzZXEuY291bnRyeS5jb3VudHMpClRQQS5yYXdzZXEuY291bnRyeS5jb3VudHMgPC0gVFBBLnJhd3NlcS5jb3VudHJ5LmNvdW50c1shaXMubmEoVFBBLnJhd3NlcS5jb3VudHJ5LmNvdW50cyRHZW9fQ291bnRyeSksXQpUUEEucmF3c2VxLmNvdW50cnkuY291bnRzJEdlb19Db3VudHJ5IDwtIGZhY3RvcihUUEEucmF3c2VxLmNvdW50cnkuY291bnRzJEdlb19Db3VudHJ5LCBsZXZlbHM9Y29udGluZW50YWwuY291bnRyeS5jb2xzLmJyZXcyJEdlb19Db3VudHJ5KQoKCnAuQ291bnRyeS50ZW1wb3JhbC5idWJibGVwbG90IDwtIGdncGxvdChUUEEucmF3c2VxLmNvdW50cnkuY291bnRzLCBhZXMoU2FtcGxlX1llYXIsIEdlb19Db3VudHJ5LCBjb2xvdXI9R2VvX0NvdW50cnkpKSArCiAgZ2VvbV9wb2ludChhbHBoYT0wLjY1LCBhZXMoc2l6ZT1Db3VudCkpICsgCiAgI2d1aWRlcyhjb2xvdXI9RkFMU0UpICsKICB0aGVtZV9saWdodCgpICsKICBzY2FsZV9zaXplX2FyZWEobWF4X3NpemUgPSA4LGJyZWFrcz1jKDEsNSwxMCwyNSw1MCw3NSwxMDApKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWU9IkNvdW50cnkiLHZhbHVlcz1jb250aW5lbnRhbC5jb3VudHJ5LmNvbHMuYnJldzIkY291bnRyeS5jb2wsIGJyZWFrcz1jb250aW5lbnRhbC5jb3VudHJ5LmNvbHMuYnJldzIkR2VvX0NvdW50cnkpICsKICB0aGVtZS50ZXh0LnNpemUgKyB0aGVtZShsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNjUsImxpbmUiKSxsZWdlbmQucG9zaXRpb249J25vbmUnKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW09YygxOTUwLDIwMjApKSArCiAgbGFicyh5PSJDb3VudHJ5IiwgeD0iU2FtcGxlIFllYXIiKQojcC5Db3VudHJ5LnRlbXBvcmFsLmJ1YmJsZXBsb3QKCnAuQ291bnRyeS50ZW1wb3JhbC5idWJibGVwbG90LmxlZ2VuZCA8LSBnZXRfbGVnZW5kKHAuQ291bnRyeS50ZW1wb3JhbC5idWJibGVwbG90ICsgdGhlbWUobGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjY1LCJsaW5lIiksbGVnZW5kLnBvc2l0aW9uPSdsZWZ0JykpCmBgYAoKYGBge3J9CnJhdy5jb3VudHJ5LmNvdW50cyA8LSBUUEEubWV0YTEuMiAlPiUgZ3JvdXBfYnkoR2VvX0NvdW50cnkpICU+JSBzdW1tYXJpc2UoQ291bnQ9bigpKQpyYXcuY291bnRyeS5jb3VudHMkR2VvX0NvdW50cnkgPC0gZmFjdG9yKHJhdy5jb3VudHJ5LmNvdW50cyRHZW9fQ291bnRyeSxsZXZlbHM9Y29udGluZW50YWwuY291bnRyeS5jb2xzLmJyZXcyJEdlb19Db3VudHJ5KQoKcC5Db3VudHJ5LmhiYXJwbG90IDwtIGdncGxvdChyYXcuY291bnRyeS5jb3VudHMsIGFlcyhDb3VudCxHZW9fQ291bnRyeSxmaWxsPUdlb19Db3VudHJ5KSkgKwogIGdlb21fYmFyaChzdGF0PSJpZGVudGl0eSIsIHBvc2l0aW9uPSJzdGFjayIsIHdpZHRoPTAuNzUpICsKICB0aGVtZV9saWdodCgpICsKICB0aGVtZS50ZXh0LnNpemUgKyB0aGVtZShsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNjUsImxpbmUiKSxsZWdlbmQucG9zaXRpb249J25vbmUnKSArCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZT0iQ291bnRyeSIsdmFsdWVzPWNvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MiRjb3VudHJ5LmNvbCwgYnJlYWtzPWNvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MiRHZW9fQ291bnRyeSkgKwogIGdlb21fdGV4dChkYXRhPXJhdy5jb3VudHJ5LmNvdW50cywgYWVzKChDb3VudCszMCksIEdlb19Db3VudHJ5LGxhYmVsPUNvdW50KSwgc2l6ZT0yLjUsIGluaGVyaXQuYWVzID0gRikgKwogIGxhYnMoeT0iQ291bnRyeSIsIHg9IlNhbXBsZXMvQ291bnRyeSIpICsKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbT1jKDAsNjI1KSkKI3AuQ291bnRyeS5oYmFycGxvdCAgCmBgYApwbG90IHRvZ2V0aGVyCmBgYHtyLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD0zLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpncmlkLmFycmFuZ2UocC5Db3VudHJ5LnRlbXBvcmFsLmJ1YmJsZXBsb3QsIHAuQ291bnRyeS5oYmFycGxvdCArIHkudGhlbWUuc3RyaXAsIG5jb2w9Miwgd2lkdGhzPWMoMywxKSkKYGBgCgoKIyBOb3csIGxldHMgdGhpbmsgYWJvdXQganVzdCB3aGF0IGxpbmVhZ2VzIGFyZSB3aGVyZQoKYGBge3J9Cm1ham9yLmxpbmVhZ2UuY291bnRyeS5zdW1tYXJ5LnNpbXBsZSA8LSBUUEEubWV0YTEuMltUUEEubWV0YTEuMiRUUEFfTGluZWFnZSAlaW4lIGMoIlNTMTQiLCJOaWNob2xzIiksXSAlPiUgZHBseXI6Omdyb3VwX2J5KFRQQV9MaW5lYWdlLEdlb19Db3VudHJ5KSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZSh0b3RhbC5zYW1wbGVzPW4oKSkKbWFqb3IubGluZWFnZS5jb3VudHJ5LnN1bW1hcnkuc2ltcGxlJEdlb19Db3VudHJ5IDwtIGZhY3RvcihtYWpvci5saW5lYWdlLmNvdW50cnkuc3VtbWFyeS5zaW1wbGUkR2VvX0NvdW50cnksIGxldmVscz1yZXYoc29ydCh1bmlxdWUobWFqb3IubGluZWFnZS5jb3VudHJ5LnN1bW1hcnkuc2ltcGxlJEdlb19Db3VudHJ5KSkpKSAKCmNvdW50cnkuc3VtbWFyeS5zaW1wbGUgPC0gVFBBLm1ldGExLjJbVFBBLm1ldGExLjIkVFBBX0xpbmVhZ2UgJWluJSBjKCJTUzE0IiwiTmljaG9scyIpLF0gJT4lIGRwbHlyOjpncm91cF9ieShHZW9fQ291bnRyeSkgJT4lIAogIGRwbHlyOjpzdW1tYXJpc2UodG90YWwuc2FtcGxlcz1uKCkpCmNvdW50cnkuc3VtbWFyeS5zaW1wbGUkR2VvX0NvdW50cnkgPC0gZmFjdG9yKGNvdW50cnkuc3VtbWFyeS5zaW1wbGUkR2VvX0NvdW50cnksIGxldmVscz1yZXYoc29ydCh1bmlxdWUoY291bnRyeS5zdW1tYXJ5LnNpbXBsZSRHZW9fQ291bnRyeSkpKSkgCmBgYAoKCmBgYHtyfQptYWpvci5saW5lYWdlLmNvdW50cnkuc3VtbWFyeS5zaW1wbGUkVFBBX0xpbmVhZ2UgPC0gZmFjdG9yKG1ham9yLmxpbmVhZ2UuY291bnRyeS5zdW1tYXJ5LnNpbXBsZSRUUEFfTGluZWFnZSwgbGV2ZWxzPXVuaXF1ZShtYWpvci5saW5lYWdlLmNvdW50cnkuc3VtbWFyeS5zaW1wbGUkVFBBX0xpbmVhZ2UpKQoKcC5tYWpvcmxpbmVhZ2UuY291bnRyeS5wcm9wcyA8LSBnZ3Bsb3QobWFqb3IubGluZWFnZS5jb3VudHJ5LnN1bW1hcnkuc2ltcGxlLCBhZXMoR2VvX0NvdW50cnksIHRvdGFsLnNhbXBsZXMsIGZpbGw9VFBBX0xpbmVhZ2UpKSArCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLHBvc2l0aW9uID0gcG9zaXRpb25fZmlsbChyZXZlcnNlID0gVFJVRSkpICsKICB0aGVtZV9saWdodCgpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoInJveWFsYmx1ZTIiLCJpbmRpYW5yZWQxIikpICsgCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1jKDAsMC41LDEpKSArCiAgY29vcmRfZmxpcCgpICsKICB0aGVtZS50ZXh0LnNpemUgKwogIGxhYnMoeT0iUHJvcG9ydGlvbiIsIHg9IkNvdW50cnkiKQpgYGAKCgpgYGB7cn0KcC5tYWpvcmxpbmVhZ2UuY291bnRyeS5jb3VudHMgPC0gZ2dwbG90KG1ham9yLmxpbmVhZ2UuY291bnRyeS5zdW1tYXJ5LnNpbXBsZSwgYWVzKEdlb19Db3VudHJ5LCB0b3RhbC5zYW1wbGVzLCBmaWxsPVRQQV9MaW5lYWdlKSkgKyAKICAgICAgICAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLHBvc2l0aW9uPSJzdGFjayIpICsKICB0aGVtZV9saWdodCgpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoInJveWFsYmx1ZTIiLCJpbmRpYW5yZWQxIikpICsKICAjc2NhbGVfeV9sb2cxMCgpICsKICBjb29yZF9mbGlwKCkgKwogIGxhYnMoZmlsbD0iVFBBIExpbmVhZ2UiLCB5PSJTYW1wbGUgQ291bnQiKSArIAogIGdlb21fdGV4dChkYXRhPWNvdW50cnkuc3VtbWFyeS5zaW1wbGUsIGFlcyhHZW9fQ291bnRyeSwgKHRvdGFsLnNhbXBsZXMrMjIpLCBsYWJlbD10b3RhbC5zYW1wbGVzKSwgc2l6ZT0yLjUsIGluaGVyaXQuYWVzID0gRikgKwogIHRoZW1lLnRleHQuc2l6ZQojcC5tYWpvcmxpbmVhZ2UuY291bnRyeS5jb3VudHMKYGBgCgoKYGBge3J9Cm1ham9yLmxpbmVhZ2UuY291bnRyeS5zdW1tYXJ5LnNpbXBsZTIgPC0gbWFqb3IubGluZWFnZS5jb3VudHJ5LnN1bW1hcnkuc2ltcGxlCm1ham9yLmxpbmVhZ2UuY291bnRyeS5zdW1tYXJ5LnNpbXBsZTIkR2VvX0NvdW50cnkgPC0gZmFjdG9yKG1ham9yLmxpbmVhZ2UuY291bnRyeS5zdW1tYXJ5LnNpbXBsZTIkR2VvX0NvdW50cnksbGV2ZWxzPWNvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MiRHZW9fQ291bnRyeSkgCgpwLm1ham9ybGluZWFnZS5jb3VudHJ5LnByb3BzLnJlb3JkZXJlZCA8LSBnZ3Bsb3QobWFqb3IubGluZWFnZS5jb3VudHJ5LnN1bW1hcnkuc2ltcGxlMiwgYWVzKEdlb19Db3VudHJ5LCB0b3RhbC5zYW1wbGVzLCBmaWxsPVRQQV9MaW5lYWdlKSkgKyAKICAjZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLHBvc2l0aW9uPSJmaWxsIiwgd2lkdGg9MC43NSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5Iixwb3NpdGlvbiA9IHBvc2l0aW9uX2ZpbGwocmV2ZXJzZT1UUlVFKSwgd2lkdGg9MC43NSkgKwogIAogIHRoZW1lX2xpZ2h0KCkgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9VFBBX0xpbmVhZ2UuY29scyRMaW5lYWdlLmNvbCwgYnJlYWtzPVRQQV9MaW5lYWdlLmNvbHMkTGluZWFnZSkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPWMoMCwwLjUsMSkpICsKICBjb29yZF9mbGlwKCkgKwogIHRoZW1lLnRleHQuc2l6ZSArCiAgbGFicyh5PSJMaW5lYWdlIFByb3BvcnRpb24iLCB4PSJDb3VudHJ5IiwgZmlsbD0iVFBBIExpbmVhZ2UiKQojcC5tYWpvcmxpbmVhZ2UuY291bnRyeS5wcm9wcy5yZW9yZGVyZWQKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9MywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI2dyaWQuYXJyYW5nZShwLkNvdW50cnkudGVtcG9yYWwuYnViYmxlcGxvdCwgcC5Db3VudHJ5LmhiYXJwbG90ICsgeS50aGVtZS5zdHJpcCxwLm1ham9ybGluZWFnZS5jb3VudHJ5LnByb3BzLnJlb3JkZXJlZCArIHkudGhlbWUuc3RyaXAgKyB0aGVtZS50ZXh0LnNpemUgKyB0aGVtZShsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNzUsImxpbmUiKSksIG5jb2w9Mywgd2lkdGhzPWMoNiwyLDIpKQpgYGAKCgpNYWpvciBsaW5lYWdlIGJ1YmJsZXBsb3QgdGltZWxpbmUKYGBge3IsIGZpZy53aWR0aD01LCBmaWcuaGVpZ2h0PTMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpUUEEubWFqb3JsaW5lYWdlLmNvdW50cyA8LSBUUEEubWV0YTEuMlsoVFBBLm1ldGExLjIkU2FtcGxlX1llYXIhPSItIiAmIFRQQS5tZXRhMS4yJFRQQV9MaW5lYWdlIT0ib3V0bGllciIpLF0gJT4lIGRwbHlyOjpncm91cF9ieShTYW1wbGVfWWVhcixUUEFfTGluZWFnZSkgJT4lIAogIGRwbHlyOjpzdW1tYXJpc2UoQ291bnQ9bigpKQoKVFBBLm1ham9ybGluZWFnZS5jb3VudHMkU2FtcGxlX1llYXIgPC0gaWZlbHNlKFRQQS5tYWpvcmxpbmVhZ2UuY291bnRzJFNhbXBsZV9ZZWFyPT0iMTk2MC0xOTgwIiwiMTk3MCIsVFBBLm1ham9ybGluZWFnZS5jb3VudHMkU2FtcGxlX1llYXIpCgpUUEEubWFqb3JsaW5lYWdlLmNvdW50cyA8LSBwbHlyOjpqb2luKGRhdGEuZnJhbWUoU2FtcGxlX1llYXI9YygxOTEyOjIwMTkpLHN0cmluZ3NBc0ZhY3RvcnM9RiksIFRQQS5tYWpvcmxpbmVhZ2UuY291bnRzKQpUUEEubWFqb3JsaW5lYWdlLmNvdW50cyA8LSBUUEEubWFqb3JsaW5lYWdlLmNvdW50c1shaXMubmEoVFBBLm1ham9ybGluZWFnZS5jb3VudHMkVFBBX0xpbmVhZ2UpLF0KVFBBLm1ham9ybGluZWFnZS5jb3VudHMkVFBBX0xpbmVhZ2UgPC0gZmFjdG9yKFRQQS5tYWpvcmxpbmVhZ2UuY291bnRzJFRQQV9MaW5lYWdlLCBsZXZlbHM9cmV2KFRQQV9MaW5lYWdlLmNvbHMkTGluZWFnZSkpCgoKcC5tYWpvcmxpbmVhZ2UudGVtcG9yYWwuYnViYmxlcGxvdCA8LSBnZ3Bsb3QoVFBBLm1ham9ybGluZWFnZS5jb3VudHMsIGFlcyhTYW1wbGVfWWVhciwgVFBBX0xpbmVhZ2UsIGNvbG91cj1UUEFfTGluZWFnZSkpICsKICBnZW9tX3BvaW50KGFscGhhPTAuNjUsIGFlcyhzaXplPUNvdW50KSkgKyAKICB0aGVtZV9saWdodCgpICsKICBzY2FsZV9zaXplX2FyZWEobWF4X3NpemUgPSA4LGJyZWFrcz1jKDEsNSwxMCwyNSw1MCw3NSwxMDApKSArCiAgI3NjYWxlX2NvbG9yX21hbnVhbChuYW1lPSJDb3VudHJ5Iix2YWx1ZXM9Y29udGluZW50YWwuY291bnRyeS5jb2xzLmJyZXcyJGNvdW50cnkuY29sLCBicmVha3M9Y29udGluZW50YWwuY291bnRyeS5jb2xzLmJyZXcyJEdlb19Db3VudHJ5KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWU9IkxpbmVhZ2UiLHZhbHVlcz1UUEFfTGluZWFnZS5jb2xzJExpbmVhZ2UuY29sLCBicmVha3M9VFBBX0xpbmVhZ2UuY29scyRMaW5lYWdlKSArCiAgdGhlbWUudGV4dC5zaXplICsgdGhlbWUobGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjY1LCJsaW5lIiksbGVnZW5kLnBvc2l0aW9uPSdub25lJykgKwogIGNvb3JkX2NhcnRlc2lhbih4bGltPWMoMTk1MCwyMDIwKSkgKwogIGxhYnMoeT0iTGluZWFnZSIsIHg9IlNhbXBsZSBZZWFyIikKcC5tYWpvcmxpbmVhZ2UudGVtcG9yYWwuYnViYmxlcGxvdAoKcC5tYWpvcmxpbmVhZ2UudGVtcG9yYWwuYnViYmxlcGxvdC5sZWdlbmQgPC0gZ2V0X2xlZ2VuZChwLm1ham9ybGluZWFnZS50ZW1wb3JhbC5idWJibGVwbG90ICsgdGhlbWUobGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjY1LCJsaW5lIiksbGVnZW5kLnBvc2l0aW9uPSdsZWZ0JykgKyBndWlkZXMoc2l6ZT1GQUxTRSkpCgoKCiMgdG90YWwgY291bnRzCiNUUEEubWFqb3JsaW5lYWdlLmNvdW50cy5zaW1wbGUgPC0gVFBBLm1ldGExLjJbKFRQQS5tZXRhMS4yJFNhbXBsZV9ZZWFyIT0iLSIgJiBUUEEubWV0YTEuMiRUUEFfTGluZWFnZSE9Im91dGxpZXIiKSxdICU+JSBkcGx5cjo6Z3JvdXBfYnkoVFBBX0xpbmVhZ2UpICU+JSAKIyAgZHBseXI6OnN1bW1hcmlzZShDb3VudD1uKCkpClRQQS5tYWpvcmxpbmVhZ2UuY291bnRzLnNpbXBsZSA8LSBUUEEubWV0YTEuMiAlPiUgZHBseXI6Omdyb3VwX2J5KFRQQV9MaW5lYWdlKSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZShDb3VudD1uKCkpCgoKCnAubWFqb3JsaW5lYWdlLnRvdGFsLmhiYXJwbG90IDwtIGdncGxvdChUUEEubWFqb3JsaW5lYWdlLmNvdW50cywgYWVzKENvdW50LFRQQV9MaW5lYWdlLCBmaWxsPVRQQV9MaW5lYWdlKSkgKwogIGdlb21fYmFyaChzdGF0PSJpZGVudGl0eSIsIHBvc2l0aW9uPSJzdGFjayIsIHdpZHRoPTAuNjUpICsgCiAgdGhlbWVfbGlnaHQoKSArCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZT0iTGluZWFnZSIsdmFsdWVzPVRQQV9MaW5lYWdlLmNvbHMkTGluZWFnZS5jb2wsIGJyZWFrcz1UUEFfTGluZWFnZS5jb2xzJExpbmVhZ2UpICsKICBnZW9tX3RleHQoZGF0YT1UUEEubWFqb3JsaW5lYWdlLmNvdW50cy5zaW1wbGUsIGFlcygoQ291bnQrMzApLCBUUEFfTGluZWFnZSwgbGFiZWw9Q291bnQpLCBzaXplPTIuNSwgaW5oZXJpdC5hZXMgPSBGKSArCiAgdGhlbWUudGV4dC5zaXplICsgdGhlbWUobGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjY1LCJsaW5lIiksbGVnZW5kLnBvc2l0aW9uPSdub25lJykgKwogIGxhYnMoeT0iTGluZWFnZSIsIHg9IkNvdW50IikgKyAKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbT1jKDAsNjI1KSkKcC5tYWpvcmxpbmVhZ2UudG90YWwuaGJhcnBsb3QKCmBgYAoKTG9vayBhdCBzYW1wbGUgZGF0ZXMgYW5kIHdoZXRoZXIgYSBzYW1wbGUgd2FzIHBhc3NhZ2VkIG9yIG5vdApgYGB7cn0KVFBBLm1ldGExLjIkU2FtcGxlX1llYXIuMjAwMGVyYSA8LSBpZmVsc2UoVFBBLm1ldGExLjIkU2FtcGxlX1llYXIubnVtPDIwMDAsInByZTIwMDAiLCJwb3N0MTk5OSIpClRQQS5tZXRhMS4yW1RQQS5tZXRhMS4yJFNhbXBsZV9OYW1lPT0iREFMLTEiLCJTYW1wbGVfWWVhci4yMDAwZXJhIl0gPC0gInByZTIwMDAiCgoKIyBQcm9wb3J0aW9uIG9mIHNhbXBsZXMgYmVmb3JlIGFuZCBhZnRlciAyMDAwClRQQS5tZXRhMS4yWyFpcy5uYShUUEEubWV0YTEuMiRTYW1wbGVfWWVhci4yMDAwZXJhKSxdICU+JSBkcGx5cjo6Z3JvdXBfYnkoU2FtcGxlX1llYXIuMjAwMGVyYSkgJT4lCiAgZHBseXI6OnN1bW1hcmlzZShjb3VudD1uKCkpICU+JSAKICBkcGx5cjo6bXV0YXRlKHBlcmM9KGNvdW50L3N1bShjb3VudCkqMTAwKSkKCgoKIyBQcm9wb3J0aW9uIG9mIGNsaW5pY2FscyBiZWZvcmUgMjAwMApkYXRhLmZyYW1lKFRQQS5tZXRhMS4yWyghaXMubmEoVFBBLm1ldGExLjIkU2FtcGxlX1llYXIuMjAwMGVyYSkgJiBUUEEubWV0YTEuMiRTYW1wbGVfWWVhci4yMDAwZXJhPT0icHJlMjAwMCIpLF0gJT4lIGRwbHlyOjpncm91cF9ieShEaXJlY3RfZnJvbV9jbGluKSAlPiUKICAgICAgICAgICAgICAgZHBseXI6OnN1bW1hcmlzZShjb3VudD1uKCkpICU+JSAKICAgICAgICAgICAgICAgZHBseXI6Om11dGF0ZShwZXJjPShjb3VudC9zdW0oY291bnQpKjEwMCkpLHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQoKIyBQcm9wb3J0aW9uIG9mIGNsaW5pY2FscyBhZnRlciAxOTk5CmRhdGEuZnJhbWUoVFBBLm1ldGExLjJbKCFpcy5uYShUUEEubWV0YTEuMiRTYW1wbGVfWWVhci4yMDAwZXJhKSAmIFRQQS5tZXRhMS4yJFNhbXBsZV9ZZWFyLjIwMDBlcmE9PSJwb3N0MTk5OSIpLF0gJT4lIGRwbHlyOjpncm91cF9ieShEaXJlY3RfZnJvbV9jbGluKSAlPiUKICAgICAgICAgICAgICAgZHBseXI6OnN1bW1hcmlzZShjb3VudD1uKCkpICU+JSAKICAgICAgICAgICAgICAgZHBseXI6Om11dGF0ZShwZXJjPShjb3VudC9zdW0oY291bnQpKjEwMCkpLHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQoKCgpgYGAKCgoKIyBEbyBhIG1hcCBvZiBzYW1wbGUgZGlzdHJpYnV0aW9ucwoKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTYsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgojY291bnRyeS5jb29yZHMuc3Vic2V0MSA8LSBkYXRhLmZyYW1lKEdlb19Db3VudHJ5PXVuaXF1ZShzdWJsaW5lYWdlLmNvdW50cnkuc3VtbWFyeS5zaW1wbGUkR2VvX0NvdW50cnkpKQpjb3VudHJ5LmNvb3Jkcy5zdWJzZXQgPC0gZGF0YS5mcmFtZShHZW9fQ291bnRyeT1yYXcuY291bnRyeS5jb3VudHMkR2VvX0NvdW50cnksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQoKY291bnRyeS5jb29yZHMuc3Vic2V0JG5hbWUgPC0gZ3N1YigiQ3plY2ggUmVwdWJsaWMiLCJDemVjaGlhIixnc3ViKCJVU0EiLCJVbml0ZWQgU3RhdGVzIixnc3ViKCJVSyIsIlVuaXRlZCBLaW5nZG9tIixnc3ViKCJcXF8iLCJcXCAiLGNvdW50cnkuY29vcmRzLnN1YnNldCRHZW9fQ291bnRyeSkpKSkKCiMgUnVzc2lhIGlzIHZlcnkgbGFyZ2UgLSBsZXQncyBjZW50cmUgb24gVHV2YSBpbnN0ZWFkIChidXQga2VlcCB0aGUgbGFiZWxsaW5nIGZvciBkYXRhYmFzZSBjb25zaXN0ZW5jeSkKY291bnRyeS5jb29yZHMuc3Vic2V0JG5hbWUgPC0gZ3N1YigiUnVzc2lhIiwgIlR1dmEiLCBjb3VudHJ5LmNvb3Jkcy5zdWJzZXQkbmFtZSkKCiMgTWVyZ2Ugd2l0aCBwdWJsaXNoZWQgY2VudHJvaWQgbG9jYXRpb25zIGFuZCBkZWR1cGxpY2F0ZQpjb3VudHJ5LmNvb3Jkcy5zdWJzZXQgPC0gcGx5cjo6am9pbihjb3VudHJ5LmNvb3Jkcy5zdWJzZXQsQ29vcmRpbmF0ZUNsZWFuZXI6OmNvdW50cnlyZWYsYnk9Im5hbWUiKQoKIyBNZXhpY28gY2VudHJlJ3Mgb2RkbHkgLSB0YWtlIHRoZSBsb2NhdGlvbiBvZiBNZXhpY28gQ2l0eSBpbnN0ZWFkCmNvdW50cnkuY29vcmRzLnN1YnNldFtjb3VudHJ5LmNvb3Jkcy5zdWJzZXQkR2VvX0NvdW50cnk9PSJNZXhpY28iLCJjZW50cm9pZC5sb24iXSA8LSBjb3VudHJ5LmNvb3Jkcy5zdWJzZXRbY291bnRyeS5jb29yZHMuc3Vic2V0JEdlb19Db3VudHJ5PT0iTWV4aWNvIiwiY2FwaXRhbC5sb24iXQpjb3VudHJ5LmNvb3Jkcy5zdWJzZXRbY291bnRyeS5jb29yZHMuc3Vic2V0JEdlb19Db3VudHJ5PT0iTWV4aWNvIiwiY2VudHJvaWQubGF0Il0gPC0gY291bnRyeS5jb29yZHMuc3Vic2V0W2NvdW50cnkuY29vcmRzLnN1YnNldCRHZW9fQ291bnRyeT09Ik1leGljbyIsImNhcGl0YWwubGF0Il0KCmNvdW50cnkuY29vcmRzLnN1YnNldCA8LSBjb3VudHJ5LmNvb3Jkcy5zdWJzZXRbIWR1cGxpY2F0ZWQoY291bnRyeS5jb29yZHMuc3Vic2V0JG5hbWUpLGMoIkdlb19Db3VudHJ5IiwibmFtZSIsImNlbnRyb2lkLmxvbiIsImNlbnRyb2lkLmxhdCIpXQoKIyBNZXJnZSB3aXRoIGNvdW50cnkgc2FtcGxlIGNvdW50cwpjb3VudHJ5LmNvb3Jkcy5zdWJzZXQuY291bnRzIDwtIHBseXI6OmpvaW4oY291bnRyeS5jb29yZHMuc3Vic2V0LHJhdy5jb3VudHJ5LmNvdW50cyxieT0iR2VvX0NvdW50cnkiKQoKCiMgZ2dtYXAKd29ybGQuZ3BzLmJvdW5kcyA8LSBjKGxlZnQ9LTEyMCwgYm90dG9tPS00NSwgcmlnaHQ9IDE1MCwgdG9wPSA3MikKc3RhbWFubWFwLmdsb2JhbDEgPC0gZ2dtYXA6OmdldF9zdGFtZW5tYXAoYmJveD13b3JsZC5ncHMuYm91bmRzLCBtYXB0eXBlID0gInRvbmVyLWxpdGUiLCB6b29tPTMpCgojIFJlZHVjZSB0aGUgaW50ZW5zaXR5IG9mIHRoZSBiYXNlbWFwICh0aGlyZCBvZiB0aGUgYWxwaGEpCnN0YW1hbm1hcC5nbG9iYWwxLmF0dHJpYnMgPC0gYXR0cmlidXRlcyhzdGFtYW5tYXAuZ2xvYmFsMSkKc3RhbWFubWFwLmdsb2JhbDEudHJhbnNwYXJlbnQgPC0gbWF0cml4KGFkanVzdGNvbG9yKHN0YW1hbm1hcC5nbG9iYWwxLCBhbHBoYS5mID0gMC41KSxucm93PW5yb3coc3RhbWFubWFwLmdsb2JhbDEpKQphdHRyaWJ1dGVzKHN0YW1hbm1hcC5nbG9iYWwxLnRyYW5zcGFyZW50KSA8LSBzdGFtYW5tYXAuZ2xvYmFsMS5hdHRyaWJzIAoKCiMgUGxvdCBtYXAgd2l0aCBjb3VudHJ5IHNhbXBsaW5nCnN0YW1hbm1hcC5nbG9iYWwxLnAgPC0gZ2dtYXAoc3RhbWFubWFwLmdsb2JhbDEudHJhbnNwYXJlbnQpCnN0YW1hbm1hcC5nbG9iYWwxLnAgPC0gc3RhbWFubWFwLmdsb2JhbDEucCArIAogICNnZW9tX3BvaW50KGRhdGE9Y291bnRyeS5jb29yZHMuc3Vic2V0LmNvdW50cywgYWVzKGNlbnRyb2lkLmxvbiwgY2VudHJvaWQubGF0LCBzaXplPUNvdW50KzAuNSksYWxwaGE9MC41MCwgc2hvdy5sZWdlbmQgPSBGKSArIAogIGdlb21fcG9pbnQoZGF0YT1jb3VudHJ5LmNvb3Jkcy5zdWJzZXQuY291bnRzLCBhZXMoY2VudHJvaWQubG9uLCBjZW50cm9pZC5sYXQsIHNpemU9Q291bnQsIGNvbG9yPUdlb19Db3VudHJ5KSxhbHBoYT0wLjgpICsKICBndWlkZXMoY29sb3VyPUZBTFNFKSArCiAgdGhlbWVfbGlnaHQoKSArCiAgdGhlbWUobGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjY1LCJsaW5lIiksbGVnZW5kLnBvc2l0aW9uPSdyaWdodCcsICkgKyBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQobmNvbD0zKSkgKwogIHRoZW1lLnRleHQuc2l6ZSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jb250aW5lbnRhbC5jb3VudHJ5LmNvbHMuYnJldzIkY291bnRyeS5jb2wsYnJlYWtzPWNvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MiRHZW9fQ291bnRyeSkgKwogICNzY2FsZV9zaXplX2FyZWEobWF4X3NpemUgPSAxMixicmVha3M9YygxLDUsMTAsMjUsNTAsMTAwLDIwMCw0MDApKSArCiAgI3NjYWxlX3NpemVfYmlubmVkKGJyZWFrcz1jKDEsNSwxMCwyNSw1MCwxMDAsMjAwLDQwMCkpICsKICBzY2FsZV9zaXplX2Jpbm5lZChyYW5nZSA9IGMoMiwgMTApLGJyZWFrcz1jKDUsMjAsNTAsMTAwLDIwMCw0MDApKSArCiAgbGFicyh5PSJMYXRpdHVkZSIsIHg9IkxvbmdpdHVkZSIsIGNvbG9yPSJDb3VudHJ5Iiwgc2l6ZT0iU2FtcGxlXG5Db3VudCIpCgoKCiNDYWlybzo6Q2Fpcm8oZmlsZT1wYXN0ZTAoRmlndXJlX291dHB1dF9kaXJlY3RvcnksICJHbG9iYWwtVFBBLmxvdy1jb3ZfX01hcC1vZi1Db3VudHJ5LWRpc3RyaWJ1dGlvbnMxMS0yMDIwLnN2ZyIpLCB3aWR0aCA9IDgwMCwgaGVpZ2h0ID0gNTAwLHR5cGU9InN2ZyIsdW5pdHMgPSAicHQiKQpzdGFtYW5tYXAuZ2xvYmFsMS5wCiNkZXYub2ZmKCkKCiNzdGFtYW5tYXAuZ2xvYmFsMS5wCmBgYAoKClBsb3QgYWxsIHRvZ2V0aGVyIGFzIGEgY29tYmluZWQgcGFuZWwgZ3JpZApgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTksIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnAuYnViYmxlLmxlZ2VuZHMuZ3JpZCA8LSBwbG90X2dyaWQocC5tYWpvcmxpbmVhZ2UudGVtcG9yYWwuYnViYmxlcGxvdC5sZWdlbmQsIHAuQ291bnRyeS50ZW1wb3JhbC5idWJibGVwbG90LmxlZ2VuZCwgbmNvbD0xLCByZWxfaGVpZ2h0cz1jKDEsMykpCgpmaXJzdF9yb3dfY291bnRyeS5kaXN0IDwtIHBsb3RfZ3JpZChzdGFtYW5tYXAuZ2xvYmFsMS5wLGxhYmVscz1jKCdBJyksbmNvbD0xLGxhYmVsX3NpemUgPSAxMSx2anVzdD0tMC4yNSkKCnJvdzIuM19jb2x1bW5fMV9jb3VudHJ5LmRpc3QgPC0gcGxvdF9ncmlkKHAuQ291bnRyeS50ZW1wb3JhbC5idWJibGVwbG90LCBwLm1ham9ybGluZWFnZS50ZW1wb3JhbC5idWJibGVwbG90LCBuY29sPTEsIHJlbF9oZWlnaHRzPWMoNCwxKSwgYWxpZ249VCwgbGFiZWxzPWMoJ0InLCdFJyksbGFiZWxfc2l6ZSA9IDExLHZqdXN0PS0wLjI1KQoKcm93Mi4zX2NvbHVtbl8yX2NvdW50cnkuZGlzdCA8LSBwbG90X2dyaWQocC5Db3VudHJ5LmhiYXJwbG90ICsgeS50aGVtZS5zdHJpcCArIGNvb3JkX2NhcnRlc2lhbih4PWMoMCw2MjApKSwgcC5tYWpvcmxpbmVhZ2UudG90YWwuaGJhcnBsb3QgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArIHkudGhlbWUuc3RyaXAgKyB0aGVtZS50ZXh0LnNpemUgKyBjb29yZF9jYXJ0ZXNpYW4oeD1jKDAsNjIwKSkgKyBsYWJzKHg9IlNhbXBsZXMvTGluZWFnZSIpLG5jb2w9MSwgcmVsX2hlaWdodHM9Yyg0LDEpLCBhbGlnbj1ULCBsYWJlbHM9YygnQycsJ0YnKSxsYWJlbF9zaXplID0gMTEsdmp1c3Q9LTAuMjUpCgpyb3cyLjNfY29sdW1uXzNfY291bnRyeS5kaXN0IDwtIHBsb3RfZ3JpZChwLm1ham9ybGluZWFnZS5jb3VudHJ5LnByb3BzLnJlb3JkZXJlZCArIHkudGhlbWUuc3RyaXAgKyB0aGVtZS50ZXh0LnNpemUgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSwgTlVMTCwgbmNvbD0xLCByZWxfaGVpZ2h0cz1jKDQsMSksbGFiZWxzPWMoJ0QnLCcnKSxsYWJlbF9zaXplID0gMTEsdmp1c3Q9LTAuMjUpCgpyb3cyLjNfY29tYmluZS5jb2x1bW5zX2NvdW50cnkuZGlzdCA8LSBwbG90X2dyaWQocm93Mi4zX2NvbHVtbl8xX2NvdW50cnkuZGlzdCwgcm93Mi4zX2NvbHVtbl8yX2NvdW50cnkuZGlzdCwgcm93Mi4zX2NvbHVtbl8zX2NvdW50cnkuZGlzdCxwLmJ1YmJsZS5sZWdlbmRzLmdyaWQscmVsX3dpZHRocz1jKDUsMiwxLDIpLCBuY29sPTQpCgpnZ19hbGxfY291bnRyeS5kaXN0LmNvbXBsZXggPC0gcGxvdF9ncmlkKGZpcnN0X3Jvd19jb3VudHJ5LmRpc3QsIHJvdzIuM19jb21iaW5lLmNvbHVtbnNfY291bnRyeS5kaXN0LCBsYWJlbHM9YygnJywgJycpLCBuY29sPTEsIHJlbF9oZWlnaHRzID0gYyg2LDUpLCBzY2FsZT0wLjk1KQoKI2dnX2FsbF9jb3VudHJ5LmRpc3QuY29tcGxleApgYGAKCgoKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCiNDYWlybzo6Q2Fpcm8oZmlsZT1wYXN0ZTAoRmlndXJlX291dHB1dF9kaXJlY3RvcnksICJGaWd1cmUxX19Db3VudHJ5LWRpc3Ryb3NfY29tcGxleF8wMi0yMDIxLnN2ZyIpLCB3aWR0aCA9IDEwMDAsIGhlaWdodCA9IDgwMCx0eXBlPSJzdmciLHVuaXRzID0gInB0IikKZ2dfYWxsX2NvdW50cnkuZGlzdC5jb21wbGV4CiNkZXYub2ZmKCkKYGBgCgoKIyMjCiMgTm93IG1vdmUgb250byBkZXRhaWxlZCBndWJiaW5zIG1hc2tlZCBwaHlsb2dlbnkgYW5kIHN1YmxpbmVhZ2UgYW5hbHlzaXMKCgpgYGB7cn0KI1RQQS5NTHRyZWUKI1RQQS5weWphci50cmVlCgojZ2d0cmVlKFRQQS5NTHRyZWUpCiNnZ3RyZWUoVFBBLnB5amFyLnRyZWUpCgojIEV4dHJhY3QgU05QIGRpc3RhbmNlcyBmcm9tIHB5amFyIHRyZWUKZWRnZS5UUEFndWJiaW5zIDwtIGRhdGEuZnJhbWUoVFBBLnB5amFyLnRyZWUkZWRnZSwgZWRnZV9udW09MTpsZW5ndGgoVFBBLnB5amFyLnRyZWUkZWRnZS5sZW5ndGgpLHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQpjb2xuYW1lcyhlZGdlLlRQQWd1YmJpbnMpPWMoInBhcmVudCIsICJub2RlIiwgImVkZ2VfbnVtIikKZWRnZS5UUEFndWJiaW5zJFNOUHMgPC0gVFBBLnB5amFyLnRyZWUkZWRnZS5sZW5ndGgKCiMgbm93IGJ1aWxkIHRyZWUKVFBBLnB5amFyLnRyZWVwbG90IDwtIGdndHJlZShUUEEucHlqYXIudHJlZSkgJTwrJSAKICBlZGdlLlRQQWd1YmJpbnMgKyBnZW9tX3RleHQoYWVzKHg9YnJhbmNoLCBsYWJlbD1TTlBzLCB2anVzdD0tLjUpLHNpemU9Myxjb2xvcj0iZ3JleTUwIikgKwogICNnZW9tX3RpcGxhYihzaXplPTIsYWxpZ249VCxvZmZzZXQ9LjAwMDEpICsKICBOVUxMClRQQS5weWphci50cmVlcGxvdCAKYGBgCgojIERvIHNvbWUgY2x1c3RlcmluZyB1c2luZyByUGluZWNvbmUgKHRha2VzIGEgbG9uZyB0aW1lLCBzbyB3cml0ZSBvdXQgdG8gZmlsZSBhbmQgcmVpbXBvcnQpCgpgYGB7cn0KI1RQQS5weWphci50cmVlLnBoeWxvIDwtIGFzLnBoeWxvKFRQQS5weWphci50cmVlKQojcGluZWNvbmUub3V0cHV0IDwtIHJQaW5lY29uZTo6cGluZWNvbmUoVFBBLnB5amFyLnRyZWUucGh5bG8sMTAsMykgIyBzdGFuZGFyZCBhcHByb2FjaCB1c2VkIGZvciBUUEEKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyB0ZXN0aW5nICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojcGluZWNvbmUub3V0cHV0LjguMyA8LSByUGluZWNvbmU6OnBpbmVjb25lKFRQQS5weWphci50cmVlLnBoeWxvLDgsMykgIyBtb2RpZnlpbmcgdG8gc2VlIHRoZSBlZmZlY3QgOC4zCiNwaW5lY29uZS5vdXRwdXQuMTIuMyA8LSByUGluZWNvbmU6OnBpbmVjb25lKFRQQS5weWphci50cmVlLnBoeWxvLDEyLDMpICMgbW9kaWZ5aW5nIHRvIHNlZSB0aGUgZWZmZWN0IDEyLjMKI3BpbmVjb25lLm91dHB1dCA8LSBwaW5lY29uZS5vdXRwdXQuMTIuMwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMgdGVzdGluZyAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCiNwaW5lY29uZS5jbHVzdGVycyA8LSBkYXRhLmZyYW1lKHBpbmVjb25lLm91dHB1dCR0YWJsZSxzdHJpbmdzQXNGYWN0b3JzID0gVCkKI3BpbmVjb25lLmNsdXN0ZXJzJFN1Yi5saW5lYWdlLnNpbmcgPC0gZ3N1YigiU2luZ2xldG9uXFxfLisiLCJTaW5nbGV0b24iLHBpbmVjb25lLmNsdXN0ZXJzJFN1Yi5saW5lYWdlLHBlcmw9VCkKI3dyaXRlLmNzdihwaW5lY29uZS5jbHVzdGVycywgZmlsZT1wYXN0ZTAoRmlndXJlX291dHB1dF9kaXJlY3RvcnksICJHbG9iYWwtVFBBLmdvb2Rjb3YuclBpbmVjb25lMTAtMy5hc3NpZ25tZW50c18yMDIwLTExLTExLmNzdiIpKQoKYGBgCgpBbHRlcm5hdGl2ZWx5LCB1c2UgYSBib290c3RyYXBwZWQgdmVyc2lvbiBvZiByUGluZWNvbmUgY2x1c3RlcnMgKHJ1biBvbiBjb21tYW5kIGxpbmUgZHVlIHRvIHRoZSB0aW1lIHRha2VuIHRvIGl0ZXJhdGUgb3ZlciAxMDAgdHJlZXMpClRlc3RpbmcgZXh0ZXJuYWwgcGluZWNvbmUgKHRvb2sgYWJvdXQgMyBocnMgdG8gcnVuIHJQaW5lY29uZSBvdmVyIDEwMCBib290c3RyYXAgdHJlZXMgZm9yIHRoZSBmdWxsIGRhdGFzZXQpCmBgYHtyfQoKcGluZWNvbmUuMTAgPC0gcmVhZC5jc3YocGluZWNvbmUuMTAuZmlsZSwgc3RyaW5nc0FzRmFjdG9ycz1GKQoKbGVuZ3RoKHVuaXF1ZShwaW5lY29uZS4xMCRTdWIubGluZWFnZSkpCgpsZW5ndGgodW5pcXVlKHBpbmVjb25lLjEwJHBpbmVjb25lXzk1KSkKbGVuZ3RoKHVuaXF1ZShwaW5lY29uZS4xMCRwaW5lY29uZV84MCkpCmxlbmd0aCh1bmlxdWUocGluZWNvbmUuMTAkcGluZWNvbmVfNTApKQpsZW5ndGgodW5pcXVlKHBpbmVjb25lLjEwJHBpbmVjb25lXzIwKSkKbGVuZ3RoKHVuaXF1ZShwaW5lY29uZS4xMCRwaW5lY29uZV81KSkKCnBsb3RfX3BpbmVjb25lLmJvb3RzdHJhcHMgPC0gZnVuY3Rpb24oZXh0ZXJuYWwucGluZWNvbmUuY2x1c3RlcmluZykgewogIGdnIDwtIGdndHJlZShUUEEuTUx0cmVlKQogIGYyIDwtIGZhY2V0X3Bsb3QoZ2csIHBhbmVsID0gInJQaW5lY29uZSBNTCB0cmVlIiwgZGF0YSA9IGV4dGVybmFsLnBpbmVjb25lLmNsdXN0ZXJpbmcsIGdlb20gPSBnZW9tX3RpbGUsIAogICAgICAgICAgICAgICAgICAgYWVzKHggPSBhcy5udW1lcmljKGZhY3RvcihTdWIubGluZWFnZSkpKSwgZmlsbCA9ICJibHVlIikKICBmMiA8LSBmYWNldF9wbG90KGYyLCBwYW5lbCA9ICJyUGluZWNvbmUgOTUlIiwgZGF0YSA9IGV4dGVybmFsLnBpbmVjb25lLmNsdXN0ZXJpbmcsIGdlb20gPSBnZW9tX3RpbGUsIAogICAgICAgICAgICAgICAgICAgYWVzKHggPSBhcy5udW1lcmljKGZhY3RvcihwaW5lY29uZV85NSkpKSwgZmlsbCA9ICJyZWQiKQogIGYyIDwtIGZhY2V0X3Bsb3QoZjIsIHBhbmVsID0gInJQaW5lY29uZSA4MCUiLCBkYXRhID0gZXh0ZXJuYWwucGluZWNvbmUuY2x1c3RlcmluZywgZ2VvbSA9IGdlb21fdGlsZSwgCiAgICAgICAgICAgICAgICAgICBhZXMoeCA9IGFzLm51bWVyaWMoZmFjdG9yKHBpbmVjb25lXzgwKSkpLCBmaWxsID0gImJsdWUiKQogIGYyIDwtIGZhY2V0X3Bsb3QoZjIsIHBhbmVsID0gInJQaW5lY29uZSA1MCUiLCBkYXRhID0gZXh0ZXJuYWwucGluZWNvbmUuY2x1c3RlcmluZywgZ2VvbSA9IGdlb21fdGlsZSwgCiAgICAgICAgICAgICAgICAgICBhZXMoeCA9IGFzLm51bWVyaWMoZmFjdG9yKHBpbmVjb25lXzUwKSkpLCBmaWxsID0gInJlZCIpCiAgZjIgPC0gZmFjZXRfcGxvdChmMiwgcGFuZWwgPSAiclBpbmVjb25lIDIwJSIsIGRhdGEgPSBleHRlcm5hbC5waW5lY29uZS5jbHVzdGVyaW5nLCBnZW9tID0gZ2VvbV90aWxlLCAKICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gYXMubnVtZXJpYyhmYWN0b3IocGluZWNvbmVfMjApKSksIGZpbGwgPSAiYmx1ZSIpCiAgZjIgPC0gZmFjZXRfcGxvdChmMiwgcGFuZWwgPSAiclBpbmVjb25lIDUlIiwgZGF0YSA9IGV4dGVybmFsLnBpbmVjb25lLmNsdXN0ZXJpbmcsIGdlb20gPSBnZW9tX3RpbGUsIAogICAgICAgICAgICAgICAgICAgYWVzKHggPSBhcy5udW1lcmljKGZhY3RvcihwaW5lY29uZV81KSkpLCBmaWxsID0gInJlZCIpICsKICAgIHRoZW1lKHN0cmlwLmJhY2tncm91bmQgPWVsZW1lbnRfcmVjdChmaWxsPSJ3aGl0ZSIpLHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0gOCkpICsKICAgIHRoZW1lLnRleHQuc2l6ZQogIHJldHVybihmMikKfQoKCnAucGluZWNvbmUuYm9vb3RzdHJhcC5jbHVzdGVyLmV2YWwgPC0gcGxvdF9fcGluZWNvbmUuYm9vdHN0cmFwcyhwaW5lY29uZS4xMCkKCiNDYWlybzo6Q2Fpcm8oZmlsZT1wYXN0ZTAoRmlndXJlX291dHB1dF9kaXJlY3RvcnksICJTdXBwbGVtZW50YXJ5X0ZpZ3VyZTNfR2xvYmFsLVRQQS5nb29kLU1MdHJlZV92c19yUGluZWNvbmUtdGhyZXNob2xkc18wMi0yMDIxLnN2ZyIpLCB3aWR0aCA9IDYwMCwgaGVpZ2h0ID0gNjAwLHR5cGU9InN2ZyIsdW5pdHMgPSAicHQiKQpwLnBpbmVjb25lLmJvb290c3RyYXAuY2x1c3Rlci5ldmFsCiNkZXYub2ZmKCkKCmBgYAoKclBpbmVjb25lIGNsdXN0ZXJzIGFyZSBkZXBlbmRlbnQgb24gYm90aCBTTlAgZGlzdGFuY2UgYW5kIHRyZWUgdG9wb2xvZ3kuIEJvb3RzdHJhcHBpbmcgdGhlc2UgY2x1c3RlcnMgaXMgdmVyeSBoYXJkLCBiZWNhdXNlIHRoZSBkYXRhIGFyZSBzbyBjbG9uYWwgLSBwYXJ0aWN1bGFybHkgYXQgdGhlIHRvcCBvZiB0aGUgdHJlZS4gUmVtb3ZpbmcganVzdCBhIGZldyBjb2x1bW5zIGZvciBhIGJvb3RzdHJhcCBjYW4gY2hhbmdlIHRoZSB0b3BvbG9neSBvZiB0aGUgdmVyeSBjbG9uYWwgY2x1c3Rlci4gSG93ZXZlciwgaXQgaXMgY2xlYXIgdGhhdCBtYW55IG9mIHRoZXNlIGNsdXN0ZXJzIGVsc2V3aGVyZSBhcmUgc3RpbGwgdmFsaWQgYW5kIHJlcHJvZHVjaWJsZSBhdCBldmVuIHZlcnkgc3RyaW5nZW50IHN1cHBvcnQgY3JpdGVyaWEuIFRoZXJlZm9yZSwgZm9yIGNvbnNpc3RlbmN5LCBkZWNpZGVkIHRvIHJlcXVpcmUgdGhlIHNhbWUgY2x1c3RlcnMgdG8gYmUgcHJlc2VudCBpbiBhdCBsZWFzdCA1JSBvZiB0cmVlcyAtIHRoaXMgcm9idXN0IGFsbG93cyBhbWFsZ2FtYXRpb24gb2YgdGhlIHRvcCBjbGFkZSBpbnRvIGEgY29oZXJlbnQgZ3JvdXAuIAoKU2luY2UgcGFwZXIgd2FzIGxhcmdlbHkgYW5hbHlzZWQgdXNpbmcgbm9uLWJvb3RzdHJhcHBlZCBjbHVzdGVycywgd2lsbCBhaW0gdG8gdXNlIHRoZSBzYW1lIG9yZGVyaW5nIHNjaGVtZSAoYnV0IG9ubHkgdXNlIHJvYnVzdCBjbHVzdGVycykuCmBgYHtyfQpwaW5lY29uZS4xMC4zX181cGMgPC0gdW5pcXVlKHBpbmVjb25lLjEwWyxjKCJTdWIubGluZWFnZSIsInBpbmVjb25lXzUiKV0pCgojIHdhbnQgdG8gcmVuYW1lIGJvb3RzdHJhcHBlZCBjbHVzdGVycyB0byBiZSByZWFzb25hYmx5IGNvbnNpc3RlbnQgd2l0aCBjb25zZW5zdXMgdHJlZSBhbmFseXNpcywgYW5kIGVuc3VyZSBzZW5zaWJsZSBvcmRlciBvbiB0cmVlKQpwaW5lY29uZS4xMC4zX181cGMgPC0gZGF0YS5mcmFtZShwaW5lY29uZS4xMCAlPiUgZHBseXI6Omdyb3VwX2J5KHBpbmVjb25lXzUpICU+JSBzdW1tYXJpc2UoY291bnQ9bigpKSkKcGluZWNvbmUuMTAuM19fNXBjJGlzLnNpbmdsZXRvbiA8LSBpZmVsc2UocGluZWNvbmUuMTAuM19fNXBjJGNvdW50PT0xLCJzaW5nbGV0b24iLCAibXVsdGkiKQpwaW5lY29uZS4xMC4zX181cGMgPC0gcGx5cjo6am9pbihwaW5lY29uZS4xMC4zX181cGMsIHVuaXF1ZShwaW5lY29uZS4xMFssYygiU3ViLmxpbmVhZ2UiLCJwaW5lY29uZV81IildKSwgYnk9InBpbmVjb25lXzUiLCB0eXBlPSdmdWxsJykKcGluZWNvbmUuMTAuM19fNXBjJFN1Yi5saW5lYWdlLnNpbmcgPC0gc2FwcGx5KDE6bnJvdyhwaW5lY29uZS4xMC4zX181cGMpLCBmdW5jdGlvbih4KSBpZmVsc2UoZ3JlcGwoInNpbmdsZXRvbiIscGluZWNvbmUuMTAuM19fNXBjJFN1Yi5saW5lYWdlW3hdKSwyMyxwaW5lY29uZS4xMC4zX181cGMkU3ViLmxpbmVhZ2VbeF0pKQpwaW5lY29uZS4xMC4zX181cGMgPC0gcGluZWNvbmUuMTAuM19fNXBjW29yZGVyKGFzLm51bWVyaWMocGluZWNvbmUuMTAuM19fNXBjJFN1Yi5saW5lYWdlLnNpbmcpLHBpbmVjb25lLjEwLjNfXzVwYyRTdWIubGluZWFnZSksXQoKIyBOb3cgZXh0cmFjdCBub24tc2luZ2xldG9ucyBhbmQgcmVuYW1lIGluIG9yZGVyCm5ldy5uYW1lcyA8LSBwaW5lY29uZS4xMC4zX181cGNbcGluZWNvbmUuMTAuM19fNXBjJFN1Yi5saW5lYWdlLnNpbmchPTIzLF0KbmV3Lm5hbWVzIDwtIGRhdGEuZnJhbWUocGluZWNvbmVfNT11bmlxdWUobmV3Lm5hbWVzJHBpbmVjb25lXzUpLCBzdHJpbmdzQXNGYWN0b3JzID0gRikKbmV3Lm5hbWVzJHBpbmVjb25lXzVfbmV3bmFtZSA8LSBjKDE6bnJvdyhuZXcubmFtZXMpKQojIE5vdyBleHRyYWN0IHNpbmdsZXRvbnMgYW5kIHJlbmFtZSAKbmV3Lm5hbWVzLnNpbmcgPC0gcGluZWNvbmUuMTAuM19fNXBjW3BpbmVjb25lLjEwLjNfXzVwYyRpcy5zaW5nbGV0b249PSJzaW5nbGV0b24iLF0KbmV3Lm5hbWVzLnNpbmcgPC0gZGF0YS5mcmFtZShwaW5lY29uZV81PXVuaXF1ZShuZXcubmFtZXMuc2luZyRwaW5lY29uZV81KSwgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCm5ldy5uYW1lcy5zaW5nJHBpbmVjb25lXzVfbmV3bmFtZSA8LSAiU2luZ2xldG9uIgojIENvbWJpbmUgbmV3IG5hbWUgbGlzdApuZXcubmFtZXMgPC0gcmJpbmQobmV3Lm5hbWVzLG5ldy5uYW1lcy5zaW5nKQojIGludGVncmF0ZSBpbnRvIGxpc3Qgb2YgdHlwZXMKcGluZWNvbmUuMTAuM19fNXBjIDwtIHBseXI6OmpvaW4ocGluZWNvbmUuMTAuM19fNXBjLCBuZXcubmFtZXMsIGJ5PSJwaW5lY29uZV81IiwgdHlwZT0nbGVmdCcpCgojIG5vdyBhcHBseSBiYWNrIHRvIHNhbXBsZXMgCnBpbmVjb25lLjEwIDwtIHBseXI6OmpvaW4ocGluZWNvbmUuMTAsICh1bmlxdWUocGluZWNvbmUuMTAuM19fNXBjWyxjKCJwaW5lY29uZV81IiwicGluZWNvbmVfNV9uZXduYW1lIildKSksIGJ5PSJwaW5lY29uZV81IiwgdHlwZT0ibGVmdCIpCnBpbmVjb25lLjEwJHBpbmVjb25lXzVfbmV3bmFtZS5udW1lcmljIDwtIGFzLm51bWVyaWMoc2FwcGx5KDE6bnJvdyhwaW5lY29uZS4xMCksIGZ1bmN0aW9uKHgpIGlmZWxzZShncmVwbCgiU2luZ2xldG9uIixwaW5lY29uZS4xMCRwaW5lY29uZV81X25ld25hbWVbeF0pLDE4LHBpbmVjb25lLjEwJHBpbmVjb25lXzVfbmV3bmFtZVt4XSkpKQoKCgpgYGAKCgpyZS1pbXBvcnQgclBpbmVjb25lIGNsYXNzaWZpY2F0aW9ucyAob3JpZ2luYWwgYW5hbHlzaXMpCmBgYHtyfQoKcGluZWNvbmUuY2x1c3RlcnMyIDwtIHJlYWQuY3N2KHBpbmVjb25lLmNsdXN0ZXJzLk1Mb3JpZ2luYWwuZmlsZSwgcm93Lm5hbWVzPTEsIGNvbW1lbnQuY2hhcj0iIiwgY2hlY2submFtZXM9RikKCgoKcGluZWNvbmUuY2x1c3RlcnMgPC0gZGF0YS5mcmFtZShwaW5lY29uZS5jbHVzdGVyczIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQoKI1RQQS5tZXRhMS4yCmNvbG5hbWVzKHBpbmVjb25lLmNsdXN0ZXJzKSA8LSBjKCJTYW1wbGVfTmFtZSIsICJwaW5lY29uZS5zdWJsaW4ucmF3IiwicGluZWNvbmUubWFqb3IubGluLnJhdyIsICJUUEEucGluZWNvbmUuc3VibGluZWFnZS5weWphciIpCgojIGRvIHNvbWUgcmVsYWJlbGxpbmcgb2YgbWFqb3IgbGluZWFnZXMKcGluZWNvbmUuY2x1c3RlcnMkVFBBLnBpbmVjb25lLm1ham9yIDwtIGlmZWxzZShwaW5lY29uZS5jbHVzdGVycyRwaW5lY29uZS5tYWpvci5saW4ucmF3PT0iMCIsIm91dGxpZXIiLCBpZmVsc2UocGluZWNvbmUuY2x1c3RlcnMkcGluZWNvbmUubWFqb3IubGluLnJhdz09IjEiLCAiU1MxNCIsICJOaWNob2xzIikpCgpgYGAKCiMgSW50ZWdyYXRlIHBpbmVjb25lIGRhdGEgd2l0aCBmdWxsIG1ldGEKYGBge3J9ClRQQS5tZXRhMS4yLnBpbmVjb25lIDwtIHBseXI6OmpvaW4ocGluZWNvbmUuY2x1c3RlcnNbLGMoIlNhbXBsZV9OYW1lIiwiVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UucHlqYXIiLCJUUEEucGluZWNvbmUubWFqb3IiKV0sIFRQQS5tZXRhMS4yLCBieT0iU2FtcGxlX05hbWUiLCB0eXBlPSJsZWZ0IikKClRQQS5tZXRhMS4yLnBpbmVjb25lIDwtIHBseXI6OmpvaW4oZGF0YS5mcmFtZShTYW1wbGVfTmFtZT1waW5lY29uZS4xMCRUYXhhLCBUUEEucGluZWNvbmUuc3VibGluZWFnZT1waW5lY29uZS4xMCRwaW5lY29uZV81X25ld25hbWUsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKSxUUEEubWV0YTEuMi5waW5lY29uZSwgYnk9IlNhbXBsZV9OYW1lIiwgdHlwZT0ibGVmdCIpCmBgYAoKYGBge3J9CiMgSG93IG1hbnkgTmljaG9scyBhcmUgdGhlcmU/Cm5yb3coVFBBLm1ldGExLjIucGluZWNvbmVbVFBBLm1ldGExLjIucGluZWNvbmUkVFBBX0xpbmVhZ2U9PSJOaWNob2xzIixdKQoKIyBIb3cgbWFueSBTUzE0IGFyZSB0aGVyZT8KbnJvdyhUUEEubWV0YTEuMi5waW5lY29uZVtUUEEubWV0YTEuMi5waW5lY29uZSRUUEFfTGluZWFnZT09IlNTMTQiLF0pCgojIEhvdyBtYW55IG91dGxpZXJzIGFyZSB0aGVyZT8gKHRoZXNlIGFyZSB0ZWNobmljYWxseSBTUzE0L05pY2hvbHMsIGJ1dCBhbHNvIGJhc2FsIGluIHRoZSBwaHlsb2dlbnkpCm5yb3coVFBBLm1ldGExLjIucGluZWNvbmVbVFBBLm1ldGExLjIucGluZWNvbmUkVFBBLnBpbmVjb25lLm1ham9yPT0ib3V0bGllciIsXSkKCiMgd2hhdCBhcmUgdGhlIG91dGxpZXIgKG5vbi1TUzE0L05paG9scykgZ2Vub21lcz8KVFBBLm1ldGExLjIucGluZWNvbmVbVFBBLm1ldGExLjIucGluZWNvbmUkVFBBLnBpbmVjb25lLm1ham9yPT0ib3V0bGllciIsXQoKIyBIb3cgbWFueSBTaW5nbGV0b25zIGFyZSB0aGVyZT8KbnJvdyhUUEEubWV0YTEuMi5waW5lY29uZVtncmVwbCgiU2luZ2xldG9uIixUUEEubWV0YTEuMi5waW5lY29uZSRUUEEucGluZWNvbmUuc3VibGluZWFnZSksXSkKKFRQQS5tZXRhMS4yLnBpbmVjb25lW2dyZXBsKCJTaW5nbGV0b24iLFRQQS5tZXRhMS4yLnBpbmVjb25lJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlKSxdKQoKIyBIb3cgbWFueSBOaWNob2xzIFNpbmdsZXRvbnMgYXJlIHRoZXJlPwpucm93KFRQQS5tZXRhMS4yLnBpbmVjb25lWyhncmVwbCgiU2luZ2xldG9uIixUUEEubWV0YTEuMi5waW5lY29uZSRUUEEucGluZWNvbmUuc3VibGluZWFnZSkgJiBUUEEubWV0YTEuMi5waW5lY29uZSRUUEFfTGluZWFnZT09Ik5pY2hvbHMiKSxdKQoKIyBIb3cgbWFueSBTUzE0IFNpbmdsZXRvbnMgYXJlIHRoZXJlPwpucm93KFRQQS5tZXRhMS4yLnBpbmVjb25lWyhncmVwbCgiU2luZ2xldG9uIixUUEEubWV0YTEuMi5waW5lY29uZSRUUEEucGluZWNvbmUuc3VibGluZWFnZSkgJiBUUEEubWV0YTEuMi5waW5lY29uZSRUUEFfTGluZWFnZT09IlNTMTQiKSxdKQooVFBBLm1ldGExLjIucGluZWNvbmVbKGdyZXBsKCJTaW5nbGV0b24iLFRQQS5tZXRhMS4yLnBpbmVjb25lJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlKSAmIFRQQS5tZXRhMS4yLnBpbmVjb25lJFRQQV9MaW5lYWdlPT0iU1MxNCIpLF0pCgpgYGAKCk9mIHRoZSBjb3VudHJpZXMgdGhhdCBoYXZlIGJvdGggTmljaG9scyBhbmQgU1MxNCwgd2hhdCBpcyB0aGUgYnJlYWtkb3duPwpgYGB7cn0KIyBXaGljaCBjb3VudHJpZXMgaGF2ZSBib3RoIFNTMTQgYW5kIE5pY2hvbHM/CkNvdW50cmllcy5ib3RoLmxpbmVhZ2VzIDwtIGRhdGEuZnJhbWUodW5pcXVlKFRQQS5tZXRhMS4yWyxjKCJHZW9fQ291bnRyeSIsIlRQQV9MaW5lYWdlIildKSAlPiUgZHBseXI6Omdyb3VwX2J5KEdlb19Db3VudHJ5KSAlPiUgZHBseXI6OnN1bW1hcmlzZShjb3VudD1uKCkpKQpDb3VudHJpZXMuYm90aC5saW5lYWdlcyA8LSBDb3VudHJpZXMuYm90aC5saW5lYWdlc1tDb3VudHJpZXMuYm90aC5saW5lYWdlcyRjb3VudD09MiwiR2VvX0NvdW50cnkiXQoKIyBQcm9wb3J0aW9uIG9mIE5pY2hvbHMvU1MxNCBpbiB0aGlzIHN1YnNldCBvZiBjb3VudHJpZXMKVFBBLm1ldGExLjJbVFBBLm1ldGExLjIkR2VvX0NvdW50cnkgJWluJSBDb3VudHJpZXMuYm90aC5saW5lYWdlcyxdICU+JSAKICBkcGx5cjo6Z3JvdXBfYnkoVFBBX0xpbmVhZ2UpICU+JQogIHN1bW1hcmlzZShjb3VudD1uKCkpICU+JQogIG11dGF0ZShwZXJjZW50YWdlPShjb3VudC9zdW0oY291bnQpKSoxMDApCgojIGFuZCBieSBjb3VudHJ5CkxpbmVhZ2UucGVyYy5jb3VudHJ5IDwtIGRhdGEuZnJhbWUoVFBBLm1ldGExLjJbVFBBLm1ldGExLjIkR2VvX0NvdW50cnkgJWluJSBDb3VudHJpZXMuYm90aC5saW5lYWdlcyxdICU+JSAKICBkcGx5cjo6Z3JvdXBfYnkoR2VvX0NvdW50cnksVFBBX0xpbmVhZ2UpICU+JQogIHN1bW1hcmlzZShjb3VudD1uKCkpICU+JQogIG11dGF0ZShwZXJjZW50YWdlPShjb3VudC9zdW0oY291bnQpKSoxMDApLHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQpMaW5lYWdlLnBlcmMuY291bnRyeQoKbWVkaWFuKExpbmVhZ2UucGVyYy5jb3VudHJ5W0xpbmVhZ2UucGVyYy5jb3VudHJ5JFRQQV9MaW5lYWdlPT0iU1MxNCIsInBlcmNlbnRhZ2UiXSkKYGBgCgoKCkRlc2NyaXB0aW9uIG9mIHRoZSBuZXcgZGF0YXNldApgYGB7cn0KIyBUb3RhbCBzYW1wbGVzIGluIGdvb2QgdHJlZQpucm93KFRQQS5tZXRhMS4yLnBpbmVjb25lKQojIFRvdGFsICduZXcnIHNhbXBsZXMgaW4gZ29vZCB0cmVlCnVuaXF1ZShUUEEubWV0YTEuMi5waW5lY29uZSRDaXRhdGlvbikKbnJvdyhUUEEubWV0YTEuMi5waW5lY29uZVtUUEEubWV0YTEuMi5waW5lY29uZSRDaXRhdGlvbiAlaW4lIGMoInVucHVibGlzaGVkLVdTSSIgLCJ1bnB1Ymxpc2hlZC1UYWlhcm9hIiksXSkKbnJvdyhUUEEubWV0YTEuMi5waW5lY29uZVtUUEEubWV0YTEuMi5waW5lY29uZSRDaXRhdGlvbiAlbm90aW4lIGMoInVucHVibGlzaGVkLVdTSSIgLCJ1bnB1Ymxpc2hlZC1UYWlhcm9hIiksXSkKCm5yb3coVFBBLm1ldGExLjIucGluZWNvbmVbVFBBLm1ldGExLjIucGluZWNvbmUkQ2l0YXRpb24gJWluJSBjKCJUaGlzX1N0dWR5IiksXSkKbnJvdyhUUEEubWV0YTEuMi5waW5lY29uZVtUUEEubWV0YTEuMi5waW5lY29uZSRDaXRhdGlvbiAlbm90aW4lIGMoIlRoaXNfU3R1ZHkiKSxdKQpgYGAKCgoKRGVmaW5lIGNvbG91cnMgZm9yIHN1YmxpbmVhZ2VzCmBgYHtyfQojIERlZmluZSBzdWJsaW5lYWdlIGNsdXN0ZXJpbmcgc2NoZW1lIHVzaW5nIGJyZXcgY29sb3Vyc2NhbGVzCiNzdWJsaW5lYWdlcy5jb2xzLmJyZXcgPC0gZGF0YS5mcmFtZSh1bmlxdWUoVFBBLm1ldGExLjIucGluZWNvbmVbLGMoIlRQQS5waW5lY29uZS5tYWpvciIsIlRQQS5waW5lY29uZS5zdWJsaW5lYWdlLnB5amFyIildKSwgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCnN1YmxpbmVhZ2VzLmNvbHMuYnJldyA8LSBkYXRhLmZyYW1lKHVuaXF1ZShUUEEubWV0YTEuMi5waW5lY29uZVssYygiVFBBLnBpbmVjb25lLm1ham9yIiwiVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UiKV0pLCBzdHJpbmdzQXNGYWN0b3JzID0gRikKCnN1YmxpbmVhZ2VzLmNvbHMuYnJldyA8LSBzdWJsaW5lYWdlcy5jb2xzLmJyZXdbb3JkZXIoc3VibGluZWFnZXMuY29scy5icmV3JFRQQS5waW5lY29uZS5tYWpvcixzdWJsaW5lYWdlcy5jb2xzLmJyZXckVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UpLF0KCnN1YmxpbmVhZ2VzLmNvbHMuYnJldyRzdWJsaW4ub3JkZXIgPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoc3VibGluZWFnZXMuY29scy5icmV3JFRQQS5waW5lY29uZS5zdWJsaW5lYWdlKSkKc3VibGluZWFnZXMuY29scy5icmV3IDwtIHN1YmxpbmVhZ2VzLmNvbHMuYnJld1tvcmRlcihzdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluLm9yZGVyKSxdCgoKCiNzdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZS5jb2xzIDwtIGMoYnJld2VyLnBhbChuPTcsIkJsdWVzIilbMjo3XSxicmV3ZXIucGFsKG49NiwiUHVycGxlcyIpWzI6Nl0sImdyZXk4MCIsYnJld2VyLnBhbChuPTQsIllsT3JCciIpW2MoMiwzKV0sIGJyZXdlci5wYWwobj03LCJSZWRzIilbMjo2XSxicmV3ZXIucGFsKG49NSwiR3JlZW5zIilbMjo1XSwiZ3JleTgwIikgCgojIEZvciByZXZpc2VkIGJvb3RzdHJhcHBlZCBjbHVzdGVycwpzdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZS5jb2xzIDwtIHN1YmxpbmVhZ2VzLmNvbHMuYnJldyRzdWJsaW5lYWdlLmNvbHMgPC0gYygiI0ZDOTI3MiIsIiNFRjNCMkMiLGJyZXdlci5wYWwobj00LCJHcmVlbnMiKVsyOjRdLGJyZXdlci5wYWwobj00LCJZbE9yQnIiKVtjKDIsMyldLGJyZXdlci5wYWwobj02LCJCbHVlcyIpWzI6Nl0sYnJld2VyLnBhbChuPTYsIlB1cnBsZXMiKVsyOjZdLCJncmV5ODAiLCJncmV5ODAiKQogIAoKCnN1YmxpbmVhZ2VzLmNvbHMuYnJldyA8LSB1bmlxdWUoc3VibGluZWFnZXMuY29scy5icmV3WyxjKCJUUEEucGluZWNvbmUuc3VibGluZWFnZSIsInN1YmxpbmVhZ2UuY29scyIpXSkKc3VibGluZWFnZXMuY29scy5icmV3IDwtIHN1YmxpbmVhZ2VzLmNvbHMuYnJld1tvcmRlcihhcy5udW1lcmljKGFzLmNoYXJhY3RlcihzdWJsaW5lYWdlcy5jb2xzLmJyZXckVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UpKSksXQpzdWJsaW5lYWdlcy5jb2xzLmJyZXckVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UgPC0gZmFjdG9yKHN1YmxpbmVhZ2VzLmNvbHMuYnJldyRUUEEucGluZWNvbmUuc3VibGluZWFnZSwgbGV2ZWxzPXN1YmxpbmVhZ2VzLmNvbHMuYnJldyRUUEEucGluZWNvbmUuc3VibGluZWFnZSkKCmNvbG5hbWVzKHN1YmxpbmVhZ2VzLmNvbHMuYnJldykgPC0gYygic3VibGluZWFnZSIsInN1YmxpbmVhZ2UuY29scyIpCnN1YmxpbmVhZ2VzLmNvbHMuYnJldyA8LSB1bmlxdWUoc3VibGluZWFnZXMuY29scy5icmV3KQoKYGBgCgoKbm93IHBsb3QgdHJlZXMKYGBge3J9CiNUUEEuTUx0cmVlLmdndHJlZSA8LSBnZ3RyZWUoVFBBLk1MdHJlZSxsYXlvdXQgPSAiZmFuIixvcGVuLmFuZ2xlID0gMjAsIHJpZ2h0PVQpCiNUUEEucHlqYXIudHJlZXBsb3QgCgpwLlRQQS5weWphci50cmVlcGxvdC50aXBzdWJsaW5lYWdlcyA8LSBUUEEucHlqYXIudHJlZXBsb3QgJTwrJSBkYXRhLmZyYW1lKFNhbXBsZV9OYW1lPVRQQS5tZXRhMS4yLnBpbmVjb25lJFNhbXBsZV9OYW1lLCBTdWJsaW5lYWdlPVRQQS5tZXRhMS4yLnBpbmVjb25lJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlLHN0cmluZ3NBc0ZhY3RvcnMgPSBGKSArIAogIGdlb21fdGlwcG9pbnQoYWVzKGNvbG9yPVN1YmxpbmVhZ2UpLCBzaXplPTEsIGFscGhhPTAuNSkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZT0iU3VibGluZWFnZSIsdmFsdWVzPXN1YmxpbmVhZ2VzLmNvbHMuYnJldyRzdWJsaW5lYWdlLmNvbHMsIGJyZWFrcz1zdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZSkgCgpwLlRQQS5weWphci50cmVlcGxvdC5zdHJpcHN1YmxpbmVhZ2VzIDwtIGdoZWF0bWFwKFRQQS5weWphci50cmVlcGxvdCwKICAgICAgICAgICAgICAgZGF0YS5mcmFtZShyb3cubmFtZXM9VFBBLm1ldGExLjIucGluZWNvbmUkU2FtcGxlX05hbWUsIFN1YmxpbmVhZ2U9VFBBLm1ldGExLjIucGluZWNvbmUkVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2Usc3RyaW5nc0FzRmFjdG9ycyA9IEYpLCBjb2xvcj1OVUxMLHdpZHRoPTAuMSxvZmZzZXQ9MC4wMDAwMDA1LCBjb2xuYW1lc19hbmdsZT0tNDUsY29sbmFtZXNfb2Zmc2V0X3k9MC4yNSwgZm9udC5zaXplPTMpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZT0iU3VibGluZWFnZSIsdmFsdWVzPXN1YmxpbmVhZ2VzLmNvbHMuYnJldyRzdWJsaW5lYWdlLmNvbHMsIGJyZWFrcz1zdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZSkgCnAuVFBBLnB5amFyLnRyZWVwbG90LnN0cmlwc3VibGluZWFnZXMKCmBgYAoKTm93IGZvciBNTCBndWJiaW5zIHRyZWUKYGBge3J9ClRQQS5NTHRyZWUuZ2d0cmVlIDwtIGdndHJlZShUUEEuTUx0cmVlLGxheW91dCA9ICJmYW4iLG9wZW4uYW5nbGUgPSAyMCwgcmlnaHQ9VCkKClRQQS5NTHRyZWUuZ2d0cmVlLnRpcHBvaW50IDwtIFRQQS5NTHRyZWUuZ2d0cmVlICU8KyUgZGF0YS5mcmFtZShTYW1wbGVfTmFtZT1UUEEubWV0YTEuMi5waW5lY29uZSRTYW1wbGVfTmFtZSwgU3VibGluZWFnZT1UUEEubWV0YTEuMi5waW5lY29uZSRUUEEucGluZWNvbmUuc3VibGluZWFnZSxzdHJpbmdzQXNGYWN0b3JzID0gRikgKyAKICBnZW9tX3RpcHBvaW50KGFlcyhjb2xvcj1TdWJsaW5lYWdlKSwgc2l6ZT0wLjc1LCBhbHBoYT0wLjUpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWU9IlN1YmxpbmVhZ2UiLHZhbHVlcz1zdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZS5jb2xzLCBicmVha3M9c3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2UpCgpwLlRQQS5NTHRyZWUuc3VibGluZWFnZXMgPC0gZ2hlYXRtYXAoVFBBLk1MdHJlZS5nZ3RyZWUudGlwcG9pbnQsCiAgICAgICAgICAgICAgIGRhdGEuZnJhbWUocm93Lm5hbWVzPVRQQS5tZXRhMS4yLnBpbmVjb25lJFNhbXBsZV9OYW1lLCBTdWJsaW5lYWdlPVRQQS5tZXRhMS4yLnBpbmVjb25lJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlLHN0cmluZ3NBc0ZhY3RvcnMgPSBGKSwgY29sb3I9TlVMTCx3aWR0aD0wLjA3NSxvZmZzZXQ9MC4wMDAwMDAyNSwgY29sbmFtZXNfYW5nbGU9LTQ1LGNvbG5hbWVzX29mZnNldF95PTAuMDIsIGhqdXN0PS0wLjAsZm9udC5zaXplPTIuMjUpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZT0iU3VibGluZWFnZSIsdmFsdWVzPXN1YmxpbmVhZ2VzLmNvbHMuYnJldyRzdWJsaW5lYWdlLmNvbHMsIGJyZWFrcz1zdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZSkgKwogIHRoZW1lLnRleHQuc2l6ZSArIHRoZW1lKGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC42NSwibGluZSIpLGxlZ2VuZC5wb3NpdGlvbj0ncmlnaHQnKQoKI3AuVFBBLk1MdHJlZS5zdWJsaW5lYWdlcwoKCiNDYWlybzo6Q2Fpcm8oZmlsZT1wYXN0ZTAoRmlndXJlX291dHB1dF9kaXJlY3RvcnksICJTdXBwbGVtZW50YXJ5X0ZpZ3VyZTJfX2dvb2Rjb3YtTUx0cmVlX2NpcmN1bGFyX18wMi0yMDIxLnN2ZyIpLCB3aWR0aCA9IDgwMCwgaGVpZ2h0ID0gODAwLHR5cGU9InN2ZyIsdW5pdHMgPSAicHQiKQpwLlRQQS5NTHRyZWUuc3VibGluZWFnZXMKI2Rldi5vZmYoKQoKCmBgYAoKCm9yIGEgbGluZWFyIHRyZWUgKHdoaWNoIGNhbiBhbHNvIGNhcHR1cmUgbGVnZW5kIGZyb20pIApgYGB7cn0KVFBBLk1MLmdndHJlZS5saW5lYXIgPC0gZ2d0cmVlKFRQQS5NTHRyZWUpICU8KyUgZGF0YS5mcmFtZShTYW1wbGVfTmFtZT1UUEEubWV0YTEuMi5waW5lY29uZSRTYW1wbGVfTmFtZSwgU3VibGluZWFnZT1UUEEubWV0YTEuMi5waW5lY29uZSRUUEEucGluZWNvbmUuc3VibGluZWFnZSxzdHJpbmdzQXNGYWN0b3JzID0gRikgKyAKICBnZW9tX3RpcHBvaW50KGFlcyhjb2xvcj1TdWJsaW5lYWdlKSwgc2l6ZT0wLjc1LCBhbHBoYT0wLjUsIHNob3cubGVnZW5kID0gRikgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZT0iU3VibGluZWFnZSIsdmFsdWVzPXN1YmxpbmVhZ2VzLmNvbHMuYnJldyRzdWJsaW5lYWdlLmNvbHMsIGJyZWFrcz1zdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZSkgKwogICMgYWRkIGJvb3RzdHJhcCBzdXBwb3J0CiAgZ2VvbV9wb2ludDIoYWVzKHN1YnNldD0oIWlzVGlwICYgYXMubnVtZXJpYyhsYWJlbCk+OTUpKSxzaXplPTEuNSwgc2hhcGU9MTgpICsKICAjZ2VvbV9wb2ludDIoYWVzKHN1YnNldD0oIWlzVGlwICYgYXMubnVtZXJpYyhsYWJlbCk+OTUpKSxzaXplPTIuNSwgc2hhcGU9MTgsIGFscGhhPTAuNSkgKwogICNnZW9tX3BvaW50MihhZXMoc3Vic2V0PSghaXNUaXAgJiBhcy5udW1lcmljKGxhYmVsKT45NSkpLHNpemU9MS41LCBzaGFwZT0xOCwgY29sb3I9J2N5YW4nLCBhbHBoYT0wLjUpICsKICBOVUxMCgpwLlRQQS5NTC5nZ3RyZWUubGluZWFyIDwtIGdoZWF0bWFwKFRQQS5NTC5nZ3RyZWUubGluZWFyLAogICAgICAgICAgICAgICBkYXRhLmZyYW1lKHJvdy5uYW1lcz1UUEEubWV0YTEuMi5waW5lY29uZSRTYW1wbGVfTmFtZSwgU3VibGluZWFnZT1UUEEubWV0YTEuMi5waW5lY29uZSRUUEEucGluZWNvbmUuc3VibGluZWFnZSxzdHJpbmdzQXNGYWN0b3JzID0gRiksIGNvbG9yPU5VTEwsd2lkdGg9MC4wNzUsb2Zmc2V0PTAuMDAwMDAwMjUsIGNvbG5hbWVzX2FuZ2xlPTAsY29sbmFtZXNfb2Zmc2V0X3k9LTEsIGZvbnQuc2l6ZT0yKSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWU9IlN1YmxpbmVhZ2UiLHZhbHVlcz1zdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZS5jb2xzLCBicmVha3M9c3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2UpICsKICB0aGVtZS50ZXh0LnNpemUgKyB0aGVtZShsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNzUsImxpbmUiKSxsZWdlbmQucG9zaXRpb249J2JvdHRvbScpCgpwLlRQQS5NTC5nZ3RyZWUubGluZWFyIDwtIHAuVFBBLk1MLmdndHJlZS5saW5lYXIgKyBuZXdfc2NhbGVfZmlsbCgpCgpwLlRQQS5NTC5nZ3RyZWUubGluZWFyIDwtIGdoZWF0bWFwKHAuVFBBLk1MLmdndHJlZS5saW5lYXIsVFBBLnJhd3NlcS5jb3VudHJpZXMucCwgY29sb3I9TlVMTCx3aWR0aD0wLjA3NSxvZmZzZXQ9MC4wMDAwMDcyNSwgY29sbmFtZXNfYW5nbGU9MCxjb2xuYW1lc19vZmZzZXRfeT0tMSwgZm9udC5zaXplPTIpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZT0iQ291bnRyeSIsdmFsdWVzPWNvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MiRjb3VudHJ5LmNvbCwgYnJlYWtzPWNvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MiRHZW9fQ291bnRyeSkgKwogIHRoZW1lLnRleHQuc2l6ZSArIHRoZW1lKGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC42NSwibGluZSIpLGxlZ2VuZC5wb3NpdGlvbj0nYm90dG9tJykgKyAKICBnZW9tX3RyZWVzY2FsZShmb250c2l6ZSA9IDIuNSwgeD0wLjAwMDAwMSwgeT01MCkgKwogIE5VTEwKCnAuVFBBLk1MLmdndHJlZS5saW5lYXIKCiMgQ2FwdHVyZSBsZWdlbmQgZnJvbSBmdWxsIHRyZWUKcC5UUEEuTUwuZ2d0cmVlLmxpbmVhci5sZWdlbmQgPC0gZ2V0X2xlZ2VuZChwLlRQQS5NTC5nZ3RyZWUubGluZWFyKQoKYGBgCgojIERlZmluZSBzdWJ0cmVlcyB1c2luZyAnY29sbGFwc2UnIGNsYWRlCmBgYHtyfQoKI2dndHJlZShUUEEuTUx0cmVlLGxheW91dCA9ICJmYW4iLG9wZW4uYW5nbGUgPSAyMCwgcmlnaHQ9VCkgKyBnZW9tX3RleHQyKGFlcyhzdWJzZXQ9IWlzVGlwLCBsYWJlbD1ub2RlKSwgaGp1c3Q9LS4zKSAKI2dndHJlZShUUEEuTUx0cmVlKSArIGdlb21fdGV4dDIoYWVzKHN1YnNldD0haXNUaXAsIGxhYmVsPW5vZGUpLCBoanVzdD0tLjMsIHNpemU9MykgCgpTUzE0LnN1YnRyZWUubm9kZWlkIDwtIDUzMCAjIDUyOQpOaWNob2xzLnN1YnRyZWUubm9kZWlkIDwtIDk1NSAKCgpgYGAKCgoKTmljaG9scyBzdWJ0cmVlICh3aXRoIGNvbGxhcHNlZCBTUzE0KQpgYGB7ciwgZmlnLndpZHRoPTQsIGZpZy5oZWlnaHQ9NSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCiNUUEEuTUwuZ2d0cmVlLmxpbmVhciArIGdlb21fdGV4dDIoYWVzKHN1YnNldD0haXNUaXAsIGxhYmVsPW5vZGUpLCBoanVzdD0tLjMsIHNpemU9MykgCgpOaWNob2xzLmNvbGwgPC0gZ2d0cmVlKFRQQS5NTHRyZWUpICU+JSBjb2xsYXBzZShub2RlPVNTMTQuc3VidHJlZS5ub2RlaWQpCgojIENvbGxhcGluZyBub2RlIHJlZHVjZXMgJ3knIHBvc2l0aW9uLCBzbyBsZXRzIGFkZCBzb21lIGJhY2sgZm9yIHByb3BlciBzcGFjaW5nCk5pY2hvbHMuY29sbCRkYXRhW05pY2hvbHMuY29sbCRkYXRhJG5vZGU9PVNTMTQuc3VidHJlZS5ub2RlaWQsInkiXSA8LSBOaWNob2xzLmNvbGwkZGF0YVtOaWNob2xzLmNvbGwkZGF0YSRub2RlPT1TUzE0LnN1YnRyZWUubm9kZWlkLCJ5Il0gKyAxMAoKIyBub3cgYWRkIHRyaWFuZ2xlIGFuZCB0ZXh0Ck5pY2hvbHMuY29sbCA8LSBOaWNob2xzLmNvbGwgKyBnZW9tX3RleHQyKGFlcyhzdWJzZXQ9KG5vZGUgPT0gU1MxNC5zdWJ0cmVlLm5vZGVpZCkpLCBzaXplPTIwLCBsYWJlbD1pbnRUb1V0ZjgoOTY2NCksIGhqdXN0PTAuMix2anVzdD0uNTUsIGZhbWlseT0iT3BlblNhbnNFbW9qaSIsIGNvbG9yPSJpbmRpYW5yZWQxIiwgYWxwaGE9Ljc1KQpOaWNob2xzLmNvbGwgPC0gTmljaG9scy5jb2xsICsgZ2VvbV90ZXh0MihhZXMoc3Vic2V0PShub2RlID09IFNTMTQuc3VidHJlZS5ub2RlaWQpKSwgY2V4PTMsIHZqdXN0PTAuMiwgbGFiZWw9IlNTMTQiLGhqdXN0ID0gLTEuNSkKTmljaG9scy5jb2xsIDwtIE5pY2hvbHMuY29sbCAlPCslIGRhdGEuZnJhbWUoU2FtcGxlX05hbWU9VFBBLm1ldGExLjIucGluZWNvbmUkU2FtcGxlX05hbWUsIFN1YmxpbmVhZ2U9VFBBLm1ldGExLjIucGluZWNvbmUkVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2Usc3RyaW5nc0FzRmFjdG9ycyA9IEYpICsgCiAgZ2VvbV90aXBwb2ludChhZXMoY29sb3I9U3VibGluZWFnZSksIHNpemU9MSwgYWxwaGE9MC4yNSxzaG93LmxlZ2VuZD1GKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lPSJTdWJsaW5lYWdlIix2YWx1ZXM9c3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2UuY29scywgYnJlYWtzPXN1YmxpbmVhZ2VzLmNvbHMuYnJldyRzdWJsaW5lYWdlKSArCiAgIyBhZGQgYm9vdHN0cmFwIHN1cHBvcnQKICBnZW9tX3BvaW50MihhZXMoc3Vic2V0PSghaXNUaXAgJiBhcy5udW1lcmljKGxhYmVsKT45NSkpLHNpemU9MS41LCBzaGFwZT0xOCkgKwogICNnZW9tX3BvaW50MihhZXMoc3Vic2V0PSghaXNUaXAgJiBhcy5udW1lcmljKGxhYmVsKT45NSkpLHNpemU9Mi41LCBzaGFwZT0xOCwgYWxwaGE9MC41KSArCiAgI2dlb21fcG9pbnQyKGFlcyhzdWJzZXQ9KCFpc1RpcCAmIGFzLm51bWVyaWMobGFiZWwpPjk1KSksc2l6ZT0xLjUsIHNoYXBlPTE4LCBjb2xvcj0iY3lhbiIsIGFscGhhPTAuNSkgKwogIE5VTEwKCgpwLlRQQS5OaWNob2xzLmNvbGwgPC0gZ2hlYXRtYXAoTmljaG9scy5jb2xsLAogICAgICAgICAgICAgICBkYXRhLmZyYW1lKHJvdy5uYW1lcz1UUEEubWV0YTEuMi5waW5lY29uZSRTYW1wbGVfTmFtZSwgU3VibGluZWFnZT1UUEEubWV0YTEuMi5waW5lY29uZSRUUEEucGluZWNvbmUuc3VibGluZWFnZSxzdHJpbmdzQXNGYWN0b3JzID0gRiksIGNvbG9yPU5VTEwsd2lkdGg9MC4wODUsb2Zmc2V0PTAuMDAwMDAwMjUsIGNvbG5hbWVzX2FuZ2xlPTAsY29sbmFtZXNfb2Zmc2V0X3k9LTEsIGZvbnQuc2l6ZT0yKSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWU9IlN1YmxpbmVhZ2UiLHZhbHVlcz1zdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZS5jb2xzLCBicmVha3M9c3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2UpICsKICB0aGVtZS50ZXh0LnNpemUgKyB0aGVtZShsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuODUsImxpbmUiKSxsZWdlbmQucG9zaXRpb249J25vbmUnKQoKcC5UUEEuTmljaG9scy5jb2xsIDwtIHAuVFBBLk5pY2hvbHMuY29sbCArIG5ld19zY2FsZV9maWxsKCkKCnAuVFBBLk5pY2hvbHMuY29sbCA8LSBnaGVhdG1hcChwLlRQQS5OaWNob2xzLmNvbGwsVFBBLnJhd3NlcS5jb3VudHJpZXMucCwgY29sb3I9TlVMTCx3aWR0aD0wLjA4NSxvZmZzZXQ9MC4wMDAwMTAyNSwgY29sbmFtZXNfYW5nbGU9MCxjb2xuYW1lc19vZmZzZXRfeT0tMSwgZm9udC5zaXplPTIpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZT0iQ291bnRyeSIsdmFsdWVzPWNvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MiRjb3VudHJ5LmNvbCwgYnJlYWtzPWNvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MiRHZW9fQ291bnRyeSkgKwogIHRoZW1lLnRleHQuc2l6ZSArIHRoZW1lKGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC43NSwibGluZSIpLGxlZ2VuZC5wb3NpdGlvbj0nbm9uZScpICsKICBnZW9tX3RyZWVzY2FsZShmb250c2l6ZSA9IDIuNSwgeD0wLjAwMDAwMiwgeT0yNSkgKyAKICB5bGltKC0zLDExNikgKwogICNnZ3RpdGxlKCJOaWNob2xzLWxpbmVhZ2UgcGh5bG9nZW55IikgKwogIE5VTEwKcC5UUEEuTmljaG9scy5jb2xsCgpgYGAKCgpTUzE0IHN1YnRyZWUgKHdpdGggY29sbGFwc2VkIE5pY2hvbHMpCmBgYHtyLCBmaWcud2lkdGg9NCwgZmlnLmhlaWdodD01LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKI1RQQS5NTC5nZ3RyZWUubGluZWFyICsgZ2VvbV90ZXh0MihhZXMoc3Vic2V0PSFpc1RpcCwgbGFiZWw9bm9kZSksIGhqdXN0PS0uMywgc2l6ZT0zKSAKClNTMTQuY29sbCA8LSBnZ3RyZWUoVFBBLk1MdHJlZSkgJT4lIGNvbGxhcHNlKG5vZGU9TmljaG9scy5zdWJ0cmVlLm5vZGVpZCkKCiMgQ29sbGFwaW5nIG5vZGUgcmVkdWNlcyAneScgcG9zaXRpb24sIHNvIGxldHMgYWRkIHNvbWUgYmFjayBmb3IgcHJvcGVyIHNwYWNpbmcKU1MxNC5jb2xsJGRhdGFbU1MxNC5jb2xsJGRhdGEkbm9kZT09TmljaG9scy5zdWJ0cmVlLm5vZGVpZCwieSJdIDwtIFNTMTQuY29sbCRkYXRhW1NTMTQuY29sbCRkYXRhJG5vZGU9PU5pY2hvbHMuc3VidHJlZS5ub2RlaWQsInkiXSAtIDI1CgpTUzE0LmNvbGwgPC0gU1MxNC5jb2xsICsgZ2VvbV90ZXh0MihhZXMoc3Vic2V0PShub2RlID09IE5pY2hvbHMuc3VidHJlZS5ub2RlaWQpKSwgc2l6ZT0yMCwgbGFiZWw9aW50VG9VdGY4KDk2NjQpLCBoanVzdD0wLjIsdmp1c3Q9LjU1LCBmYW1pbHk9Ik9wZW5TYW5zRW1vamkiLCBjb2xvcj0icm95YWxibHVlMiIsIGFscGhhPS44NSkKU1MxNC5jb2xsIDwtIFNTMTQuY29sbCArIGdlb21fdGV4dDIoYWVzKHN1YnNldD0obm9kZSA9PSBOaWNob2xzLnN1YnRyZWUubm9kZWlkKSksIGNleD0zLCB2anVzdD0wLjIsIGxhYmVsPSJOaWNob2xzIixoanVzdCA9IC0xKQpTUzE0LmNvbGwgPC0gU1MxNC5jb2xsICU8KyUgZGF0YS5mcmFtZShTYW1wbGVfTmFtZT1UUEEubWV0YTEuMi5waW5lY29uZSRTYW1wbGVfTmFtZSwgU3VibGluZWFnZT1UUEEubWV0YTEuMi5waW5lY29uZSRUUEEucGluZWNvbmUuc3VibGluZWFnZSxzdHJpbmdzQXNGYWN0b3JzID0gRikgKyAKICBnZW9tX3RpcHBvaW50KGFlcyhjb2xvcj1TdWJsaW5lYWdlKSwgc2l6ZT0xLCBhbHBoYT0wLjI1LHNob3cubGVnZW5kPUYpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWU9IlN1YmxpbmVhZ2UiLHZhbHVlcz1zdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZS5jb2xzLCBicmVha3M9c3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2UpICsKICAjIGFkZCBib290c3RyYXAgc3VwcG9ydAogIGdlb21fcG9pbnQyKGFlcyhzdWJzZXQ9KCFpc1RpcCAmIGFzLm51bWVyaWMobGFiZWwpPjk1KSksc2l6ZT0xLjUsIHNoYXBlPTE4KSArCiAgI2dlb21fcG9pbnQyKGFlcyhzdWJzZXQ9KCFpc1RpcCAmIGFzLm51bWVyaWMobGFiZWwpPjk1KSksc2l6ZT0yLjAsIHNoYXBlPTE4LCBhbHBoYT0wLjI1KSArCiAgI2dlb21fcG9pbnQyKGFlcyhzdWJzZXQ9KCFpc1RpcCAmIGFzLm51bWVyaWMobGFiZWwpPjk1KSksc2l6ZT0xLjUsIHNoYXBlPTE4LCBjb2xvcj0iY3lhbiIsIGFscGhhPTAuNSkgKwogIE5VTEwKI1NTMTQuY29sbAoKCnAuVFBBLlNTMTQuY29sbCA8LSBnaGVhdG1hcChTUzE0LmNvbGwsCiAgICAgICAgICAgICAgIGRhdGEuZnJhbWUocm93Lm5hbWVzPVRQQS5tZXRhMS4yLnBpbmVjb25lJFNhbXBsZV9OYW1lLCBTdWJsaW5lYWdlPVRQQS5tZXRhMS4yLnBpbmVjb25lJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlLHN0cmluZ3NBc0ZhY3RvcnMgPSBGKSwgY29sb3I9TlVMTCx3aWR0aD0wLjA4NSxvZmZzZXQ9MC4wMDAwMDAyNSwgY29sbmFtZXNfYW5nbGU9MCxjb2xuYW1lc19vZmZzZXRfeT0tMSwgZm9udC5zaXplPTIpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZT0iU3VibGluZWFnZSIsdmFsdWVzPXN1YmxpbmVhZ2VzLmNvbHMuYnJldyRzdWJsaW5lYWdlLmNvbHMsIGJyZWFrcz1zdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZSkgKwogIHRoZW1lLnRleHQuc2l6ZSArIHRoZW1lKGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC42NSwibGluZSIpLGxlZ2VuZC5wb3NpdGlvbj0nbm9uZScpCgpwLlRQQS5TUzE0LmNvbGwgPC0gcC5UUEEuU1MxNC5jb2xsICsgbmV3X3NjYWxlX2ZpbGwoKQoKcC5UUEEuU1MxNC5jb2xsIDwtIGdoZWF0bWFwKHAuVFBBLlNTMTQuY29sbCxUUEEucmF3c2VxLmNvdW50cmllcy5wLCBjb2xvcj1OVUxMLHdpZHRoPTAuMDg1LG9mZnNldD0wLjAwMDAxMDI1LCBjb2xuYW1lc19hbmdsZT0wLGNvbG5hbWVzX29mZnNldF95PS0xLCBmb250LnNpemU9MikgKyAKICBzY2FsZV9maWxsX21hbnVhbChuYW1lPSJDb3VudHJ5Iix2YWx1ZXM9Y29udGluZW50YWwuY291bnRyeS5jb2xzLmJyZXcyJGNvdW50cnkuY29sLCBicmVha3M9Y29udGluZW50YWwuY291bnRyeS5jb2xzLmJyZXcyJEdlb19Db3VudHJ5KSArCiAgdGhlbWUudGV4dC5zaXplICsgdGhlbWUobGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjY1LCJsaW5lIiksbGVnZW5kLnBvc2l0aW9uPSdub25lJykgKwogIGdlb21fdHJlZXNjYWxlKGZvbnRzaXplID0gMi41LCB4PTAuMDAwMDAyLCB5PTY1KSArCiAgI2dndGl0bGUoIlNTMTQtbGluZWFnZSBwaHlsb2dlbnkiKSArCiAgeWxpbSgtMzAsNDI5KSArCiAgTlVMTAoKcC5UUEEuU1MxNC5jb2xsCgpgYGAKClBsb3QgY29sbGFwc2VkIHRyZWVzIHRvZ2V0aGVyCmBgYHtyLCBmaWcud2lkdGg9OSwgZmlnLmhlaWdodD03LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKIyBtYWtlIE5pY2hvbHMgdHJlZSBzaG9ydGVyCmNvbGwudHJlZXMubmljaG9scy5zaG9ydGVyIDwtIHBsb3RfZ3JpZChOVUxMLCBwLlRQQS5OaWNob2xzLmNvbGwsIE5VTEwsIG5jb2w9MSwgcmVsX2hlaWdodHM9YygyLDcsMSkpCgojY29sbC50cmVlcy5yb3cuMSA8LSBwbG90X2dyaWQocC5UUEEuTmljaG9scy5jb2xsLHAuVFBBLlNTMTQuY29sbCxuY29sPTIsIHJlbF93aWR0aHM9YygxLDEpLCBsYWJlbHM9YygnTmljaG9scycsJ1NTMTQnKSxsYWJlbF9zaXplID0gMTEpCiNjb2xsLnRyZWVzLnJvdy4xIDwtIHBsb3RfZ3JpZChwLlRQQS5OaWNob2xzLmNvbGwscC5UUEEuU1MxNC5jb2xsLG5jb2w9MiwgcmVsX3dpZHRocz1jKDEsMSksIGxhYmVscz1jKCdBJywnQicpLGxhYmVsX3NpemUgPSAxMSkKCiNjb2xsLnRyZWVzLnJvdy4xIDwtIHBsb3RfZ3JpZChjb2xsLnRyZWVzLm5pY2hvbHMuc2hvcnRlcixwLlRQQS5TUzE0LmNvbGwsbmNvbD0yLCByZWxfd2lkdGhzPWMoMSwxKSwgbGFiZWxzPWMoJ0EnLCdCJyksbGFiZWxfc2l6ZSA9IDExKQpjb2xsLnRyZWVzLnJvdy4xIDwtIHBsb3RfZ3JpZChwLlRQQS5TUzE0LmNvbGwsY29sbC50cmVlcy5uaWNob2xzLnNob3J0ZXIsbmNvbD0yLCByZWxfd2lkdGhzPWMoMSwxKSwgbGFiZWxzPWMoJ0EgLSBTUzE0LWxpbmVhZ2UgcGh5bG9nZW55JywnQiAtIE5pY2hvbHMtbGluZWFnZSBwaHlsb2dlbnknKSxsYWJlbF9zaXplID0gMTEpCgoKY29sbC50cmVlcy5yb3cuMiA8LSBwbG90X2dyaWQocC5UUEEuTUwuZ2d0cmVlLmxpbmVhci5sZWdlbmQsbmNvbD0xLGxhYmVscz0nS2V5JyxsYWJlbF9zaXplID0gMTEpCmNvbGwudHJlZXMuY29tYmluZWQgPC0gcGxvdF9ncmlkKGNvbGwudHJlZXMucm93LjEsIGNvbGwudHJlZXMucm93LjIsIG5jb2w9MSwgcmVsX2hlaWdodHM9YygzLDEpLCBzY2FsZT0wLjk1KQoKY29sbC50cmVlcy5jb21iaW5lZApgYGAKCgpTdWJsaW5lYWdlIHRpbWVsaW5lIGJ1YmJsZXBsb3QKYGBge3IsIGZpZy53aWR0aD01LCBmaWcuaGVpZ2h0PTMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgojVFBBLnN1YmxpbmVhZ2VzLmNvdW50cyA8LSBUUEEubWV0YTEuMi5waW5lY29uZVsoVFBBLm1ldGExLjIucGluZWNvbmUkU2FtcGxlX1llYXIhPSItIiAmIFRQQS5tZXRhMS4yLnBpbmVjb25lJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlIT0iU2luZ2xldG9uIiksXSAlPiUgZHBseXI6Omdyb3VwX2J5KFNhbXBsZV9ZZWFyLCBUUEEucGluZWNvbmUuc3VibGluZWFnZSkgJT4lIAojICBkcGx5cjo6c3VtbWFyaXNlKENvdW50PW4oKSkKClRQQS5zdWJsaW5lYWdlcy5jb3VudHMgPC0gVFBBLm1ldGExLjIucGluZWNvbmVbKFRQQS5tZXRhMS4yLnBpbmVjb25lJFNhbXBsZV9ZZWFyIT0iLSIgKSxdICU+JSBkcGx5cjo6Z3JvdXBfYnkoU2FtcGxlX1llYXIsIFRQQS5waW5lY29uZS5zdWJsaW5lYWdlKSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZShDb3VudD1uKCkpCgoKClRQQS5zdWJsaW5lYWdlcy5jb3VudHMkU2FtcGxlX1llYXIgPC0gaWZlbHNlKFRQQS5zdWJsaW5lYWdlcy5jb3VudHMkU2FtcGxlX1llYXI9PSIxOTYwLTE5ODAiLCIxOTcwIixUUEEuc3VibGluZWFnZXMuY291bnRzJFNhbXBsZV9ZZWFyKQoKVFBBLnN1YmxpbmVhZ2VzLmNvdW50cyA8LSBwbHlyOjpqb2luKGRhdGEuZnJhbWUoU2FtcGxlX1llYXI9YygxOTEyOjIwMTkpLHN0cmluZ3NBc0ZhY3RvcnM9RiksIFRQQS5zdWJsaW5lYWdlcy5jb3VudHMpClRQQS5zdWJsaW5lYWdlcy5jb3VudHMgPC0gVFBBLnN1YmxpbmVhZ2VzLmNvdW50c1shaXMubmEoVFBBLnN1YmxpbmVhZ2VzLmNvdW50cyRUUEEucGluZWNvbmUuc3VibGluZWFnZSksXQpUUEEuc3VibGluZWFnZXMuY291bnRzJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlIDwtIGZhY3RvcihUUEEuc3VibGluZWFnZXMuY291bnRzJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlLCBsZXZlbHM9cmV2KHN1YmxpbmVhZ2VzLmNvbHMuYnJldyRzdWJsaW5lYWdlKSkKCgpwLnN1YmxpbmVhZ2UudGVtcG9yYWwuYnViYmxlcGxvdCA8LSBnZ3Bsb3QoVFBBLnN1YmxpbmVhZ2VzLmNvdW50cywgYWVzKFNhbXBsZV9ZZWFyLCBUUEEucGluZWNvbmUuc3VibGluZWFnZSwgY29sb3VyPVRQQS5waW5lY29uZS5zdWJsaW5lYWdlKSkgKwogIGdlb21fcG9pbnQoYWxwaGE9MC42NSwgYWVzKHNpemU9Q291bnQpKSArIAogIGd1aWRlcyhjb2xvdXI9RkFMU0UpICsKICB0aGVtZV9saWdodCgpICsKICBzY2FsZV9zaXplX2FyZWEobWF4X3NpemUgPSA4LGJyZWFrcz1jKDEsNSwxMCwyNSw1MCw3NSwxMDApKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWU9IlN1YmxpbmVhZ2UiLHZhbHVlcz1zdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZS5jb2xzLCBicmVha3M9c3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2UpICsKICB0aGVtZS50ZXh0LnNpemUgKyB0aGVtZShsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNjUsImxpbmUiKSxsZWdlbmQucG9zaXRpb249J3JpZ2h0JykgKwogIGNvb3JkX2NhcnRlc2lhbih4bGltPWMoMTk1MCwyMDIwKSkgKwogIGxhYnMoeT0iU3VibGluZWFnZSIsIHg9IlNhbXBsZSBZZWFyIikKCnAuc3VibGluZWFnZS50ZW1wb3JhbC5idWJibGVwbG90LmxlZ2VuZCA8LSBnZXRfbGVnZW5kKHAuc3VibGluZWFnZS50ZW1wb3JhbC5idWJibGVwbG90KQoKcC5zdWJsaW5lYWdlLnRlbXBvcmFsLmJ1YmJsZXBsb3QKYGBgCgoKYGBge3J9CiNzdWJsaW5lYWdlLmNvdW50cyA8LSBUUEEubWV0YTEuMi5waW5lY29uZVsoVFBBLm1ldGExLjIucGluZWNvbmUkU2FtcGxlX1llYXIhPSItIiAmIFRQQS5tZXRhMS4yLnBpbmVjb25lJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlIT0iU2luZ2xldG9uIiksXSAlPiUgZ3JvdXBfYnkoVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UpICU+JSBzdW1tYXJpc2UoQ291bnQ9bigpKQpzdWJsaW5lYWdlLmNvdW50cyA8LSBUUEEubWV0YTEuMi5waW5lY29uZVsoVFBBLm1ldGExLjIucGluZWNvbmUkU2FtcGxlX1llYXIhPSItIiApLF0gJT4lIGdyb3VwX2J5KFRQQS5waW5lY29uZS5zdWJsaW5lYWdlKSAlPiUgc3VtbWFyaXNlKENvdW50PW4oKSkKCgpzdWJsaW5lYWdlLmNvdW50cyRUUEEucGluZWNvbmUuc3VibGluZWFnZSA8LSBmYWN0b3Ioc3VibGluZWFnZS5jb3VudHMkVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UsbGV2ZWxzPXJldihzdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZSkpCgpwLnN1YmxpbmVhZ2UuaGJhcnBsb3QgPC0gZ2dwbG90KHN1YmxpbmVhZ2UuY291bnRzLCBhZXMoQ291bnQsVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UsZmlsbD1UUEEucGluZWNvbmUuc3VibGluZWFnZSkpICsKICBnZW9tX2Jhcmgoc3RhdD0iaWRlbnRpdHkiLCBwb3NpdGlvbj0ic3RhY2siLCB3aWR0aD0wLjc1KSArCiAgdGhlbWVfbGlnaHQoKSArCiAgdGhlbWUudGV4dC5zaXplICsgdGhlbWUobGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjY1LCJsaW5lIiksbGVnZW5kLnBvc2l0aW9uPSdub25lJykgKwogICNzY2FsZV9maWxsX21hbnVhbChuYW1lPSJDb3VudHJ5Iix2YWx1ZXM9c3VibGluZWFnZS5jb3VudHMkVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UsIGJyZWFrcz1zdWJsaW5lYWdlLmNvdW50cyRHZW9fQ291bnRyeSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWU9IlN1YmxpbmVhZ2UiLHZhbHVlcz1zdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZS5jb2xzLCBicmVha3M9c3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2UpICsKICBnZW9tX3RleHQoZGF0YT1zdWJsaW5lYWdlLmNvdW50cywgYWVzKChDb3VudCsxMCksIFRQQS5waW5lY29uZS5zdWJsaW5lYWdlLGxhYmVsPUNvdW50KSwgc2l6ZT0yLjUsIGluaGVyaXQuYWVzID0gRikgKwogIGxhYnMoeT0iU3VibGluZWFnZSIsIHg9IlNhbXBsZXMvU3VibGluZWFnZSIpCnAuc3VibGluZWFnZS5oYmFycGxvdCAgCmBgYApQcm9wb3J0aW9uIGJ5IGNvdW50cnkKYGBge3J9CiNzdWJsaW5lYWdlLmNvdW50cnkuY291bnRzIDwtIFRQQS5tZXRhMS4yLnBpbmVjb25lWyhUUEEubWV0YTEuMi5waW5lY29uZSRTYW1wbGVfWWVhciE9Ii0iICYgVFBBLm1ldGExLjIucGluZWNvbmUkVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UhPSJTaW5nbGV0b24iKSxdICU+JSBncm91cF9ieShUUEEucGluZWNvbmUuc3VibGluZWFnZSwgR2VvX0NvdW50cnkpICU+JSBzdW1tYXJpc2UoQ291bnQ9bigpKQpzdWJsaW5lYWdlLmNvdW50cnkuY291bnRzIDwtIFRQQS5tZXRhMS4yLnBpbmVjb25lWyhUUEEubWV0YTEuMi5waW5lY29uZSRTYW1wbGVfWWVhciE9Ii0iICksXSAlPiUgZ3JvdXBfYnkoVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UsIEdlb19Db3VudHJ5KSAlPiUgc3VtbWFyaXNlKENvdW50PW4oKSkKCnN1YmxpbmVhZ2UuY291bnRyeS5jb3VudHMkVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UgPC0gZmFjdG9yKHN1YmxpbmVhZ2UuY291bnRyeS5jb3VudHMkVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UsbGV2ZWxzPXJldihzdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZSkpCgpwLnN1YmxpbmVhZ2UuY291bnRyeS5oYmFycGxvdCA8LSBnZ3Bsb3Qoc3VibGluZWFnZS5jb3VudHJ5LmNvdW50cywgYWVzKENvdW50LFRQQS5waW5lY29uZS5zdWJsaW5lYWdlLGZpbGw9R2VvX0NvdW50cnkpKSArCiAgZ2VvbV9iYXJoKHN0YXQ9ImlkZW50aXR5IiwgcG9zaXRpb249ImZpbGwiLCB3aWR0aD0wLjc1KSArCiAgdGhlbWVfbGlnaHQoKSArCiAgdGhlbWUudGV4dC5zaXplICsgdGhlbWUobGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjY1LCJsaW5lIiksbGVnZW5kLnBvc2l0aW9uPSdub25lJykgKwogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWU9IkNvdW50cnkiLHZhbHVlcz1jb250aW5lbnRhbC5jb3VudHJ5LmNvbHMuYnJldzIkY291bnRyeS5jb2wsIGJyZWFrcz1jb250aW5lbnRhbC5jb3VudHJ5LmNvbHMuYnJldzIkR2VvX0NvdW50cnkpICsKICBsYWJzKHk9IlN1YmxpbmVhZ2UiLCB4PSJDb3VudHJ5IFByb3BvcnRpb24iKQpwLnN1YmxpbmVhZ2UuY291bnRyeS5oYmFycGxvdApgYGAKCgpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwLnN1YmxpbmVhZ2UudGltZWxpbmUuYnViYmxlcGxvdC5jb21iaW5lZCA8LSBwbG90X2dyaWQocC5zdWJsaW5lYWdlLnRlbXBvcmFsLmJ1YmJsZXBsb3QgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSwgcC5zdWJsaW5lYWdlLmhiYXJwbG90ICsgeS50aGVtZS5zdHJpcCwgcC5zdWJsaW5lYWdlLmNvdW50cnkuaGJhcnBsb3QgKyB5LnRoZW1lLnN0cmlwLCBwLnN1YmxpbmVhZ2UudGVtcG9yYWwuYnViYmxlcGxvdC5sZWdlbmQsIG5jb2w9NCwgYWxpZ249VCwgcmVsX3dpZHRocz1jKDUsMiwyLDEpLGxhYmVscz1jKCdDJywnRCcsJ0UnLCcnKSxsYWJlbF9zaXplID0gMTEsdmp1c3Q9LTAuMjUpICMrIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0icmlnaHQiKQoKCmdnLmNvbGx0cmVlcy5zdWJsaW5lYWdlLmRpc3RyaWJ1dGlvbnMgPC0gcGxvdF9ncmlkKGNvbGwudHJlZXMuY29tYmluZWQsIHAuc3VibGluZWFnZS50aW1lbGluZS5idWJibGVwbG90LmNvbWJpbmVkLCBuY29sPTEsIHJlbF9oZWlnaHRzPWMoNSwyKSkKI2dnLmNvbGx0cmVlcy5zdWJsaW5lYWdlLmRpc3RyaWJ1dGlvbnMKCgpgYGAKCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgojQ2Fpcm86OkNhaXJvKGZpbGU9cGFzdGUwKEZpZ3VyZV9vdXRwdXRfZGlyZWN0b3J5LCAiRmlndXJlMl9fZ29vZGNvdi1NTHRyZWVfK3N1YmxpbmVhZ2UtZGlzdHJvc19fMDItMjAyMS5zdmciKSwgd2lkdGggPSA5MDAsIGhlaWdodCA9IDkwMCx0eXBlPSJzdmciLHVuaXRzID0gInB0IikKZ2cuY29sbHRyZWVzLnN1YmxpbmVhZ2UuZGlzdHJpYnV0aW9ucwojZGV2Lm9mZigpCmBgYAoKCgojIE5vdyB0YWtlIGEgZGVlcCBkaXZlIGludG8gU2luZ2xlIGNvdW50cnkvcmVnaW9uIHN1YmxpbmVhZ2UgZHluYW1pY3MgKFVLLXdpZGUgdi5zLiBCcml0aXNoIENvbHVtYmlhLCBDYW5hZGEpCgpgYGB7cn0KClRQQS5zdWJsaW5lYWdlX1VLLkNhbmFkYS50ZW1wb3JhbCA8LSBUUEEubWV0YTEuMi5waW5lY29uZVsoVFBBLm1ldGExLjIucGluZWNvbmUkR2VvX0NvdW50cnk9PSJVSyIgfCBUUEEubWV0YTEuMi5waW5lY29uZSRHZW9fUmVnaW9uPT0iQnJpdGlzaF9Db2x1bWJpYSIpLF0KClRQQS5zdWJsaW5lYWdlX1VLLkNhbmFkYS50ZW1wb3JhbC5jb3VudHMgPC0gZGF0YS5mcmFtZShUUEEuc3VibGluZWFnZV9VSy5DYW5hZGEudGVtcG9yYWwgJT4lIGRwbHlyOjpncm91cF9ieShUUEEucGluZWNvbmUuc3VibGluZWFnZSxTYW1wbGVfWWVhcixHZW9fQ291bnRyeSxUUEEucGluZWNvbmUubWFqb3IpICU+JSAKICBkcGx5cjo6c3VtbWFyaXNlKFNhbXBsZS5Db3VudD1uKCkpLCBzdHJpbmdzQXNGYWN0b3JzID0gRikKCgojIEZpeCBkYXRlcyBhbmQgbWFrZSBjb250aW51b3VzClRQQS5zdWJsaW5lYWdlX1VLLkNhbmFkYS50ZW1wb3JhbC5jb3VudHMkU2FtcGxlX1llYXIgPC0gYXMubnVtZXJpYyhUUEEuc3VibGluZWFnZV9VSy5DYW5hZGEudGVtcG9yYWwuY291bnRzJFNhbXBsZV9ZZWFyKQoKClRQQS5zdWJsaW5lYWdlX1VLLkNhbmFkYS50ZW1wb3JhbC5jb3VudHMgPC0gcGx5cjo6am9pbihkYXRhLmZyYW1lKFNhbXBsZV9ZZWFyPWMoMTkxMjoyMDE5KSxzdHJpbmdzQXNGYWN0b3JzPUYpLFRQQS5zdWJsaW5lYWdlX1VLLkNhbmFkYS50ZW1wb3JhbC5jb3VudHMsIGJ5PSJTYW1wbGVfWWVhciIsIHR5cGU9ImxlZnQiKQoKVFBBLnN1YmxpbmVhZ2VfVUsuQ2FuYWRhLnRlbXBvcmFsLmNvdW50cyA8LSBUUEEuc3VibGluZWFnZV9VSy5DYW5hZGEudGVtcG9yYWwuY291bnRzWyFpcy5uYShUUEEuc3VibGluZWFnZV9VSy5DYW5hZGEudGVtcG9yYWwuY291bnRzJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlKSxdCgojIG9yZGVyIGJ5IHN1YmxpbmVhZ2UKVFBBLnN1YmxpbmVhZ2VfVUsuQ2FuYWRhLnRlbXBvcmFsLmNvdW50cyRUUEEucGluZWNvbmUuc3VibGluZWFnZSA8LSBmYWN0b3IoVFBBLnN1YmxpbmVhZ2VfVUsuQ2FuYWRhLnRlbXBvcmFsLmNvdW50cyRUUEEucGluZWNvbmUuc3VibGluZWFnZSwgbGV2ZWxzPXJldihzdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZSkpCgojIG1ha2UgYnViYmxlcGxvdApwbG90LlRQQS5zdWJsaW5lYWdlX1VLLkNhbmFkYS50ZW1wb3JhbC5jb3VudHMuYnViYmxlcGxvdCA8LSAKICBnZ3Bsb3QoVFBBLnN1YmxpbmVhZ2VfVUsuQ2FuYWRhLnRlbXBvcmFsLmNvdW50cywgYWVzKFNhbXBsZV9ZZWFyLCBUUEEucGluZWNvbmUuc3VibGluZWFnZSwgY29sb3I9VFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UpKSArCiAgZ2VvbV9wb2ludChhbHBoYT0wLjcwLGFlcyhzaXplPVNhbXBsZS5Db3VudCkpICsgCiAgZ2VvbV9saW5lKGFscGhhPTAuMjUpICsKICB0aGVtZV9saWdodCgpICsKICBsYWJzKHg9IlNhbXBsZSBZZWFyIiwgeT0iU3VibGluZWFnZSIsIHNpemU9IlNhbXBsZSBDb3VudCIpICsKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbT1jKDIwMDAsMjAyMCkpICsKICB0aGVtZShzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwKSkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZT0iU3VibGluZWFnZSIsdmFsdWVzPXN1YmxpbmVhZ2VzLmNvbHMuYnJldyRzdWJsaW5lYWdlLmNvbHMsIGJyZWFrcz1zdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZSkgKwogIGZhY2V0X2dyaWQoLn5HZW9fQ291bnRyeSkgKyAKICBzY2FsZV9zaXplX2FyZWEobWF4X3NpemUgPSAxMCxicmVha3M9YygxLDUsMTAsMjAsMzAsNDAsNTApKSArCiAgdGhlbWUudGV4dC5zaXplICsgCiAgdGhlbWUobGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjY1LCJsaW5lIikpICsKICB0aGVtZShzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG9yPSd3aGl0ZScsIGZpbGw9J3doaXRlJyxsaW5ldHlwZT0ic29saWQiKSwgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gImdyZXkyNSIpKSArCiAgTlVMTApwbG90LlRQQS5zdWJsaW5lYWdlX1VLLkNhbmFkYS50ZW1wb3JhbC5jb3VudHMuYnViYmxlcGxvdCAKCgpgYGAKCmdldCBwb3B1bGF0aW9uIHByZXZhbGVuY2Ugc3RhdHMKYGBge3J9CgpVSy5zdGF0cyA8LSByZWFkLnRhYmxlKFVLLnN0YXRzLmZpbGUsc2VwPSJcdCIsaGVhZGVyPVQpClVLLnN0YXRzJENvdW50cnkgPC0gIlVLIgoKCkJDLnN0YXRzIDwtIHJlYWQudGFibGUoQkMuc3RhdHMuZmlsZSxzZXA9Ilx0IixoZWFkZXI9VCkKQkMuc3RhdHMkQ291bnRyeSA8LSAiQnJpdGlzaCBDb2x1bWJpYSIKClVLLkJDLnN0YXRzLmNvbWJpbmVkIDwtIHJiaW5kKFVLLnN0YXRzLEJDLnN0YXRzKQpVSy5CQy5zdGF0cy5jb21iaW5lZFtVSy5CQy5zdGF0cy5jb21iaW5lZCRDb3VudHJ5PT0iVUsiLCJDb3VudHJ5Il0gPC0gIkVuZ2xhbmQiCgoKcGxvdC5VSy5CQy5zdGF0cy5jb21iaW5lZCA8LSBnZ3Bsb3QoVUsuQkMuc3RhdHMuY29tYmluZWQsIGFlcyhZZWFyLFRvdGFsKSkgKyAKICBnZW9tX2xpbmUoKSArCiAgdGhlbWVfbGlnaHQoKSArCiAgbGFicyh4PSJZZWFyIix5PSJTeXBoaWxpcyBJbmNpZGVuY2UvMTAwLDAwMCIpICsgCiAgI3NjYWxlX3hfY29udGludW91cyhicmVha3M9c2VxKDIwMDgsMjAxOSwyKSkgKwogIGNvb3JkX2NhcnRlc2lhbih4bGltPWMoMjAwMCwyMDIwKSkgKwogICNnZ3RpdGxlKCJTeXBoaWxpcyBJbmNpZGVuY2UgZGF0YSIpICsKICBmYWNldF9ncmlkKC5+Q291bnRyeSkgKwogIHRoZW1lLnRleHQuc2l6ZSArCiAgdGhlbWUoc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPSd3aGl0ZScsbGluZXR5cGU9InNvbGlkIiksIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJncmV5MjUiLCBzaXplPTEwKSkKcGxvdC5VSy5CQy5zdGF0cy5jb21iaW5lZAoKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTUuNSwgZmlnLmhlaWdodD00LjUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBsb3RfZ3JpZChwbG90LlVLLkJDLnN0YXRzLmNvbWJpbmVkICsgeC50aGVtZS5zdHJpcCArIGdndGl0bGUoIlN5cGhpbGlzIEluY2lkZW5jZSBhbmQgc3VibGluZWFnZSBjb3VudCIpLCBwbG90LlRQQS5zdWJsaW5lYWdlX1VLLkNhbmFkYS50ZW1wb3JhbC5jb3VudHMuYnViYmxlcGxvdCArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIixzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLHN0cmlwLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSksIG5jb2w9MSwgYWxpZ249VCwgcmVsX2hlaWdodHM9YygxLDIpLCBsYWJlbHM9YygnQScsJ0InKSwgbGFiZWxfc2l6ZT0xMSkKCmBgYAoKc29tZSBzdGF0cyBhYm91dCB0aGUgY2FuYWRpYW4gb3V0YnJlYWsKYGBge3J9CkJDLnN1YmxpbmVhZ2Uuc3VtbWFyeSA8LSBkYXRhLmZyYW1lKFRQQS5tZXRhMS4yLnBpbmVjb25lW1RQQS5tZXRhMS4yLnBpbmVjb25lJEdlb19SZWdpb249PSJCcml0aXNoX0NvbHVtYmlhIixdICU+JSBkcGx5cjo6Z3JvdXBfYnkoVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UsR2VvX0NvdW50cnksVFBBLnBpbmVjb25lLm1ham9yKSAlPiUgZHBseXI6OnN1bW1hcmlzZShTYW1wbGUuQ291bnQ9bigpKSwgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCgooQkMuc3VibGluZWFnZS5zdW1tYXJ5W0JDLnN1YmxpbmVhZ2Uuc3VtbWFyeSRUUEEucGluZWNvbmUuc3VibGluZWFnZT09MSwiU2FtcGxlLkNvdW50Il0vc3VtKEJDLnN1YmxpbmVhZ2Uuc3VtbWFyeSRTYW1wbGUuQ291bnQpKSoxMDAKCkJDLnN1YmxpbmVhZ2Uuc3VtbWFyeS5wcmUyMDEwIDwtIGRhdGEuZnJhbWUoVFBBLm1ldGExLjIucGluZWNvbmVbKFRQQS5tZXRhMS4yLnBpbmVjb25lJEdlb19SZWdpb249PSJCcml0aXNoX0NvbHVtYmlhIiAmIFRQQS5tZXRhMS4yLnBpbmVjb25lJFNhbXBsZV9ZZWFyPD0yMDEwKSxdICU+JSBkcGx5cjo6Z3JvdXBfYnkoVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UsR2VvX0NvdW50cnksVFBBLnBpbmVjb25lLm1ham9yKSAlPiUgZHBseXI6OnN1bW1hcmlzZShTYW1wbGUuQ291bnQ9bigpKSwgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCgooQkMuc3VibGluZWFnZS5zdW1tYXJ5LnByZTIwMTBbQkMuc3VibGluZWFnZS5zdW1tYXJ5LnByZTIwMTAkVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2U9PTEsIlNhbXBsZS5Db3VudCJdL3N1bShCQy5zdWJsaW5lYWdlLnN1bW1hcnkucHJlMjAxMCRTYW1wbGUuQ291bnQpKSoxMDAKCkJDLnN1YmxpbmVhZ2Uuc3VtbWFyeS5wb3N0MjAxMSA8LSBkYXRhLmZyYW1lKFRQQS5tZXRhMS4yLnBpbmVjb25lWyhUUEEubWV0YTEuMi5waW5lY29uZSRHZW9fUmVnaW9uPT0iQnJpdGlzaF9Db2x1bWJpYSIgJiBUUEEubWV0YTEuMi5waW5lY29uZSRTYW1wbGVfWWVhcj49MjAxMSksXSAlPiUgZHBseXI6Omdyb3VwX2J5KFRQQS5waW5lY29uZS5zdWJsaW5lYWdlLEdlb19Db3VudHJ5LFRQQS5waW5lY29uZS5tYWpvcikgJT4lIGRwbHlyOjpzdW1tYXJpc2UoU2FtcGxlLkNvdW50PW4oKSksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQoKKEJDLnN1YmxpbmVhZ2Uuc3VtbWFyeS5wb3N0MjAxMVtCQy5zdWJsaW5lYWdlLnN1bW1hcnkucG9zdDIwMTEkVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2U9PTEsIlNhbXBsZS5Db3VudCJdL3N1bShCQy5zdWJsaW5lYWdlLnN1bW1hcnkucG9zdDIwMTEkU2FtcGxlLkNvdW50KSkqMTAwCgpgYGAKYW5kIHRoZSBVSyBkYXRhc2V0CmBgYHtyfQpVSy5zdWJsaW5lYWdlLnN1bW1hcnkgPC0gZGF0YS5mcmFtZShUUEEubWV0YTEuMi5waW5lY29uZVtUUEEubWV0YTEuMi5waW5lY29uZSRHZW9fQ291bnRyeT09IlVLIixdICU+JSBkcGx5cjo6Z3JvdXBfYnkoVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UsR2VvX0NvdW50cnksVFBBLnBpbmVjb25lLm1ham9yKSAlPiUgZHBseXI6OnN1bW1hcmlzZShTYW1wbGUuQ291bnQ9bigpKSwgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCgpgYGAKClwKIyBOb3cgbG9vayBtb3JlIGdsb2JhbGx5IFwKU3VibGluZWFnZXMgcGVyIGNvdW50cnkgLSBub3RlIHRoYXQgdGhpcyBwbG90IGRvZXMgbm90IGFjY291bnQgZm9yIG11bHRpcGxlIFNpbmdsZXRvbnMgYmVpbmcgaW4gdGhlIHNhbWUgY291bnRyeSAtIHJlcGxhY2VkLgpgYGB7cn0Kc3VibGluZWFnZS5jb3VudC5wZXIuY291bnRyeSA8LSBkYXRhLmZyYW1lKHVuaXF1ZShUUEEubWV0YTEuMi5waW5lY29uZVssYygiVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UiLCJHZW9fQ291bnRyeSIpXSkgJT4lIGRwbHlyOjpncm91cF9ieShHZW9fQ291bnRyeSkgJT4lCiAgZHBseXI6OnN1bW1hcmlzZShjb3VudD1uKCkpLCBzdHJpbmdzQXNGYWN0b3JzID0gRikKCnN1YmxpbmVhZ2UuY291bnQucGVyLmNvdW50cnkkR2VvX0NvdW50cnkgPC0gZmFjdG9yKHN1YmxpbmVhZ2UuY291bnQucGVyLmNvdW50cnkkR2VvX0NvdW50cnksIGxldmVscz1jb250aW5lbnRhbC5jb3VudHJ5LmNvbHMuYnJldzIkR2VvX0NvdW50cnkpCgoKcC5zdWJsaW5lYWdlcy5wZXIuY291bnRyeS5iYXIgPC0gZ2dwbG90KHN1YmxpbmVhZ2UuY291bnQucGVyLmNvdW50cnksIGFlcyhHZW9fQ291bnRyeSwgY291bnQsIGZpbGw9R2VvX0NvdW50cnkpKSArIAogIGdlb21fYmFyKHN0YXQ9J2lkZW50aXR5Jywgd2lkdGg9MC43NSkgKyAKICBzY2FsZV9maWxsX21hbnVhbChuYW1lPSJDb3VudHJ5Iix2YWx1ZXM9Y29udGluZW50YWwuY291bnRyeS5jb2xzLmJyZXcyJGNvdW50cnkuY29sLCBicmVha3M9Y29udGluZW50YWwuY291bnRyeS5jb2xzLmJyZXcyJEdlb19Db3VudHJ5KSArIAogIHRoZW1lX2xpZ2h0KCkgKwogIHgudGhlbWUuYXhpcy5yb3RhdGUgKyAKICB0aGVtZS50ZXh0LnNpemUgKwogIGxhYnMoeD0iQ291bnRyeSIsIHk9IlN1YmxpbmVhZ2VzL0NvdW50cnkiKSArCiAgdGhlbWUobGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjY1LCJsaW5lIiksbGVnZW5kLnBvc2l0aW9uPSdib3R0b20nKSArIAogIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKDAsMTQsMikpCgpwLnN1YmxpbmVhZ2VzLnBlci5jb3VudHJ5LmJhcgpgYGAKCkxvb2sgYXQgU2luZ2xldG9uLCBwcml2YXRlLCBhbmQgbXVsdGktY291bnRyeSBzdWJsaW5lYWdlcwpgYGB7cn0KIyBIb3cgbWFueSBTaW5nbGV0b24gbGluZWFnZXMgYXJlIGluIGVhY2ggY291bnRyeT8KU2luZ2xldG9uLmNvdW50cnkuY291bnRzIDwtIGRhdGEuZnJhbWUoVFBBLm1ldGExLjIucGluZWNvbmVbVFBBLm1ldGExLjIucGluZWNvbmUkVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2U9PSJTaW5nbGV0b24iLGMoIlNhbXBsZV9OYW1lIiwiR2VvX0NvdW50cnkiKV0gJT4lIAogIGRwbHlyOjpncm91cF9ieShHZW9fQ291bnRyeSkgJT4lCiAgZHBseXI6OnN1bW1hcmlzZShwZXIuY291bnRyeT1uKCkpLCBzdHJpbmdzQXNGYWN0b3JzID0gRikKU2luZ2xldG9uLmNvdW50cnkuY291bnRzIDwtIHBseXI6OmpvaW4oZGF0YS5mcmFtZShHZW9fQ291bnRyeT1jKHVuaXF1ZShUUEEubWV0YTEuMi5waW5lY29uZSRHZW9fQ291bnRyeSkpKSwgU2luZ2xldG9uLmNvdW50cnkuY291bnRzLCBieT0iR2VvX0NvdW50cnkiLCB0eXBlPSJsZWZ0IikKU2luZ2xldG9uLmNvdW50cnkuY291bnRzW2lzLm5hKFNpbmdsZXRvbi5jb3VudHJ5LmNvdW50cyRwZXIuY291bnRyeSksInBlci5jb3VudHJ5Il0gPC0gMApTaW5nbGV0b24uY291bnRyeS5jb3VudHMkbGluZWFnZS50eXBlIDwtICJTaW5nbGV0b24gaW4gY291bnRyeSIKClNpbmdsZXRvbi5jb3VudHJ5LmNvdW50cwpUUEEubWV0YTEuMi5waW5lY29uZVtUUEEubWV0YTEuMi5waW5lY29uZSRUUEEucGluZWNvbmUuc3VibGluZWFnZT09IlNpbmdsZXRvbiIsIlRQQV9MaW5lYWdlIl0KClByaXZhdGUuY291bnRyeS5jb3VudHMgPC0gdW5pcXVlKFRQQS5tZXRhMS4yLnBpbmVjb25lW1RQQS5tZXRhMS4yLnBpbmVjb25lJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlIT0iU2luZ2xldG9uIixjKCJUUEEucGluZWNvbmUuc3VibGluZWFnZSIsICJHZW9fQ291bnRyeSIpXSkgJT4lIAogIGRwbHlyOjpncm91cF9ieShUUEEucGluZWNvbmUuc3VibGluZWFnZSkgJT4lCiAgc3VtbWFyaXNlKENvdW50cmllcy5jb3VudD1uKCksLmdyb3Vwcz0ia2VlcCIpClByaXZhdGUuY291bnRyeS5jb3VudHMkcHJpdmF0ZS5kaXN0cm8gPC0gaWZlbHNlKFByaXZhdGUuY291bnRyeS5jb3VudHMkQ291bnRyaWVzLmNvdW50PT0xLCJwcml2YXRlIiwibXVsdGljb3VudHJ5IikKClByaXZhdGUuY291bnRyeS5jb3VudHMKCiMgSG93IG1hbnkgcHJpdmF0ZSBsaW5lYWdlcyBhcmUgaW4gZWFjaCBjb3VudHJ5PwpQcml2YXRlLmNvdW50cnkubG9jYXRpb25zIDwtIHVuaXF1ZShUUEEubWV0YTEuMi5waW5lY29uZVtUUEEubWV0YTEuMi5waW5lY29uZSRUUEEucGluZWNvbmUuc3VibGluZWFnZSAlaW4lIGFzLmNoYXJhY3Rlcih1bmxpc3QoUHJpdmF0ZS5jb3VudHJ5LmNvdW50c1tQcml2YXRlLmNvdW50cnkuY291bnRzJHByaXZhdGUuZGlzdHJvPT0ncHJpdmF0ZScsIlRQQS5waW5lY29uZS5zdWJsaW5lYWdlIl0pKSxjKGMoIlRQQS5waW5lY29uZS5zdWJsaW5lYWdlIiwgIkdlb19Db3VudHJ5IikpXSkKUHJpdmF0ZS5jb3VudHJ5LmxvY2F0aW9uLmNvdW50cyA8LSBQcml2YXRlLmNvdW50cnkubG9jYXRpb25zICU+JSBkcGx5cjo6Z3JvdXBfYnkoR2VvX0NvdW50cnkpICU+JQogIGRwbHlyOjpzdW1tYXJpc2UocGVyLmNvdW50cnk9bigpKQpQcml2YXRlLmNvdW50cnkubG9jYXRpb24uY291bnRzIDwtIHBseXI6OmpvaW4oZGF0YS5mcmFtZShHZW9fQ291bnRyeT1jKHVuaXF1ZShUUEEubWV0YTEuMi5waW5lY29uZSRHZW9fQ291bnRyeSkpLHN0cmluZ3NBc0ZhY3RvcnMgPSBGKSwgUHJpdmF0ZS5jb3VudHJ5LmxvY2F0aW9uLmNvdW50cywgYnk9Ikdlb19Db3VudHJ5IiwgdHlwZT0ibGVmdCIpClByaXZhdGUuY291bnRyeS5sb2NhdGlvbi5jb3VudHNbaXMubmEoUHJpdmF0ZS5jb3VudHJ5LmxvY2F0aW9uLmNvdW50cyRwZXIuY291bnRyeSksInBlci5jb3VudHJ5Il0gPC0gMApQcml2YXRlLmNvdW50cnkubG9jYXRpb24uY291bnRzJGxpbmVhZ2UudHlwZSA8LSAiUHJpdmF0ZSBzdWJsaW5lYWdlIHRvIGNvdW50cnkiCgojIEhvdyBtYW55IG11bHRpY291bnRyeSBsaW5lYWdlcyBhcmUgaW4gZWFjaCBjb3VudHJ5PwptdWx0aS5jb3VudHJ5LmxvY2F0aW9ucy5jb3VudHMgPC0gdW5pcXVlKFRQQS5tZXRhMS4yLnBpbmVjb25lW1RQQS5tZXRhMS4yLnBpbmVjb25lJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlICVpbiUgYXMuY2hhcmFjdGVyKHVubGlzdChQcml2YXRlLmNvdW50cnkuY291bnRzW1ByaXZhdGUuY291bnRyeS5jb3VudHMkcHJpdmF0ZS5kaXN0cm89PSdtdWx0aWNvdW50cnknLCJUUEEucGluZWNvbmUuc3VibGluZWFnZSJdKSksYyhjKCJUUEEucGluZWNvbmUuc3VibGluZWFnZSIsICJHZW9fQ291bnRyeSIpKV0pCm11bHRpLmNvdW50cnkubG9jYXRpb25zLmNvdW50cyA8LSBtdWx0aS5jb3VudHJ5LmxvY2F0aW9ucy5jb3VudHMgJT4lIGRwbHlyOjpncm91cF9ieShHZW9fQ291bnRyeSkgJT4lCiAgZHBseXI6OnN1bW1hcmlzZShwZXIuY291bnRyeT1uKCkpCm11bHRpLmNvdW50cnkubG9jYXRpb25zLmNvdW50cyA8LSBwbHlyOjpqb2luKGRhdGEuZnJhbWUoR2VvX0NvdW50cnk9Yyh1bmlxdWUoVFBBLm1ldGExLjIucGluZWNvbmUkR2VvX0NvdW50cnkpKSxzdHJpbmdzQXNGYWN0b3JzID0gRiksIG11bHRpLmNvdW50cnkubG9jYXRpb25zLmNvdW50cywgYnk9Ikdlb19Db3VudHJ5IiwgdHlwZT0ibGVmdCIpCm11bHRpLmNvdW50cnkubG9jYXRpb25zLmNvdW50c1tpcy5uYShtdWx0aS5jb3VudHJ5LmxvY2F0aW9ucy5jb3VudHMkcGVyLmNvdW50cnkpLCJwZXIuY291bnRyeSJdIDwtIDAKbXVsdGkuY291bnRyeS5sb2NhdGlvbnMuY291bnRzJGxpbmVhZ2UudHlwZSA8LSAiTXVsdGktY291bnRyeSBzdWJsaW5lYWdlIgoKY2xhc3NpZmllZC5zdWJsaW5lYWdlcy5wZXIuY291bnRyeSA8LSByYmluZChtdWx0aS5jb3VudHJ5LmxvY2F0aW9ucy5jb3VudHMsUHJpdmF0ZS5jb3VudHJ5LmxvY2F0aW9uLmNvdW50cyxTaW5nbGV0b24uY291bnRyeS5jb3VudHMpCmNsYXNzaWZpZWQuc3VibGluZWFnZXMucGVyLmNvdW50cnkkR2VvX0NvdW50cnkgPC0gZmFjdG9yKGNsYXNzaWZpZWQuc3VibGluZWFnZXMucGVyLmNvdW50cnkkR2VvX0NvdW50cnksIGxldmVscz1jb250aW5lbnRhbC5jb3VudHJ5LmNvbHMuYnJldzIkR2VvX0NvdW50cnkpCmNsYXNzaWZpZWQuc3VibGluZWFnZXMucGVyLmNvdW50cnkkbGluZWFnZS50eXBlIDwtIGZhY3RvcihjbGFzc2lmaWVkLnN1YmxpbmVhZ2VzLnBlci5jb3VudHJ5JGxpbmVhZ2UudHlwZSwgbGV2ZWxzPXJldih1bmlxdWUoY2xhc3NpZmllZC5zdWJsaW5lYWdlcy5wZXIuY291bnRyeSRsaW5lYWdlLnR5cGUpKSkKCnBsb3QuY2xhc3NpZmllZC5zdWJsaW5lYWdlcy5wZXIuY291bnRyeSA8LSBnZ3Bsb3QoY2xhc3NpZmllZC5zdWJsaW5lYWdlcy5wZXIuY291bnRyeSwgYWVzKEdlb19Db3VudHJ5LCBwZXIuY291bnRyeSwgZmlsbD1saW5lYWdlLnR5cGUpKSArCiAgZ2VvbV9iYXIocG9zaXRpb249InN0YWNrIiwgc3RhdD0iaWRlbnRpdHkiLCB3aWR0aD0wLjc1KSArCiAgdGhlbWVfbGlnaHQoKSArIAogIHRoZW1lLnRleHQuc2l6ZSArIAogIHgudGhlbWUuYXhpcy5yb3RhdGUgKwogIGxhYnMoeD0iQ291bnRyeSIseT0iU3VibGluZWFnZS9Db3VudHJ5IiwgZmlsbD0iU3VibGluZWFnZSBUeXBlIikgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKDAsMTgsMikpICsKICB0aGVtZShsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNjUsImxpbmUiKSxsZWdlbmQucG9zaXRpb249J3JpZ2h0JykgKyAKICBnZ3RpdGxlKCJTdWJsaW5lYWdlIHR5cGVzIGJ5IGNvdW50cnkiKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJncmV5ODAiLCJncmV5NTAiLCJncmV5MTAiKSkKcGxvdC5jbGFzc2lmaWVkLnN1YmxpbmVhZ2VzLnBlci5jb3VudHJ5CgpwbG90LmNsYXNzaWZpZWQuc3VibGluZWFnZXMucGVyLmNvdW50cnkuaGJhciA8LSBnZ3Bsb3QoY2xhc3NpZmllZC5zdWJsaW5lYWdlcy5wZXIuY291bnRyeSwgYWVzKHBlci5jb3VudHJ5LEdlb19Db3VudHJ5LCBmaWxsPWxpbmVhZ2UudHlwZSkpICsKICBnZW9tX2JhcmgocG9zaXRpb249InN0YWNrIiwgc3RhdD0iaWRlbnRpdHkiLCB3aWR0aD0wLjc1KSArCiAgdGhlbWVfbGlnaHQoKSArIAogIHRoZW1lLnRleHQuc2l6ZSArIAogICN4LnRoZW1lLmF4aXMucm90YXRlICsKICBsYWJzKHk9IkNvdW50cnkiLHg9IlN1YmxpbmVhZ2UgQ291bnQiLCBmaWxsPSJTdWJsaW5lYWdlIFR5cGUiKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1zZXEoMCwxOCwyKSkgKwogIHRoZW1lKGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC42NSwibGluZSIpLGxlZ2VuZC5wb3NpdGlvbj0ncmlnaHQnKSArIAogICNnZ3RpdGxlKCJTdWJsaW5lYWdlIHR5cGVzIGJ5IGNvdW50cnkiKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJncmV5ODAiLCJncmV5NTAiLCJncmV5MTAiKSkKcGxvdC5jbGFzc2lmaWVkLnN1YmxpbmVhZ2VzLnBlci5jb3VudHJ5LmhiYXIKCgojcGxvdF9ncmlkKHAuc3VibGluZWFnZXMucGVyLmNvdW50cnkuYmFyICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKyBnZ3RpdGxlKCJOdW1iZXIgb2Ygc3VibGluZWFnZXMgaW4gZWFjaCBjb3VudHJ5IikgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTApKSArIHgudGhlbWUuc3RyaXAsIHBsb3QuY2xhc3NpZmllZC5zdWJsaW5lYWdlcy5wZXIuY291bnRyeSArdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iKSwgYWxpZ249VCwgbmNvbD0xLCByZWxfaGVpZ2h0cz1jKDEsMykpCmBgYAoKTG9vayBhdCBudW1iZXIgb2YgY291bnRyaWVzIGZvciBlYWNoIHN1YmxpbmVhZ2UgKHYucy4gc2FtcGxpbmcgY291bnRzKQpgYGB7cn0Kc3VibGluZWFnZS5jb3VudHJ5LmRpc3Ryby52cy50b3RhbC5jb3VudHMgPC0gcGx5cjo6am9pbihkYXRhLmZyYW1lKFByaXZhdGUuY291bnRyeS5jb3VudHMsc3RyaW5nc0FzRmFjdG9ycyA9IEYpLCBzdWJsaW5lYWdlLmNvdW50cywgYnk9IlRQQS5waW5lY29uZS5zdWJsaW5lYWdlIiwgdHlwZT0ibGVmdCIpCgojbGlicmFyeShnZ3JlcGVsKQpnZ3Bsb3Qoc3VibGluZWFnZS5jb3VudHJ5LmRpc3Ryby52cy50b3RhbC5jb3VudHMsIGFlcyhDb3VudCwgQ291bnRyaWVzLmNvdW50LCBzaXplPUNvdW50LCBjb2xvdXI9VFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UpKSArCiAgZ2VvbV9qaXR0ZXIoYWxwaGE9MC43NSkgKyAKICAjZ2VvbV9sYWJlbF9yZXBlbChkYXRhPXN1YmxpbmVhZ2UuY291bnRyeS5kaXN0cm8udnMudG90YWwuY291bnRzLCBhZXMoQ291bnQsIENvdW50cmllcy5jb3VudCwgbGFiZWw9VFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UpLCBzZWdtZW50LmNvbG9yID0gJ2dyZXk1MCcsIGluaGVyaXQuYWVzID0gRiwgc2l6ZT0yLjUsIGJveC5wYWRkaW5nPTAuNzUpICsKICAjZ2VvbV9wb2ludChhbHBoYT0wLjc1KSArIAogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lPSJTdWJsaW5lYWdlIix2YWx1ZXM9c3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2UuY29scywgYnJlYWtzPXN1YmxpbmVhZ2VzLmNvbHMuYnJldyRzdWJsaW5lYWdlKSArIAogIHRoZW1lX2xpZ2h0KCkgKyAKICBzY2FsZV9zaXplX2Jpbm5lZChyYW5nZSA9IGMoMSwgMTApLGJyZWFrcz1jKDUsMjAsNTAsMTAwLDIwMCw0MDApKSArCiAgc2NhbGVfeF9sb2cxMCgpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgwLDIwLDIpKSArCiAgbGFicyh5PSJDb3VudHJpZXMgKENvdW50KSIsIHg9IlNhbXBsZXMgKENvdW50KSIsIHNpemU9IlNhbXBsZSBDb3VudCIpICsKICB0aGVtZShsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNjUsImxpbmUiKSxsZWdlbmQucG9zaXRpb249J2JvdHRvbScpIAoKYGBgCgpTdW1tYXJ5IG9mIHN1YmxpbmVhZ2UgY2xhc3NpZmljYXRpb25zCmBgYHtyfQoKc3VibGluZWFnZS5jbGFzc2lmaWNhdGlvbiA8LSBQcml2YXRlLmNvdW50cnkuY291bnRzCnN1YmxpbmVhZ2UuY2xhc3NpZmljYXRpb24gPC0gc3VibGluZWFnZS5jbGFzc2lmaWNhdGlvbltvcmRlcihhcy5udW1lcmljKHN1YmxpbmVhZ2UuY2xhc3NpZmljYXRpb24kVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UpKSxdCgojIEhvdyBtYW55IHByaXZhdGUgc3VibGluZWFnZXM/Cm5yb3coc3VibGluZWFnZS5jbGFzc2lmaWNhdGlvbltzdWJsaW5lYWdlLmNsYXNzaWZpY2F0aW9uJHByaXZhdGUuZGlzdHJvPT0ncHJpdmF0ZScsXSkKIyBIb3cgbWFueSBtdWx0LWNvdW50cnkgc3VibGluZWFnZXM/Cm5yb3coc3VibGluZWFnZS5jbGFzc2lmaWNhdGlvbltzdWJsaW5lYWdlLmNsYXNzaWZpY2F0aW9uJHByaXZhdGUuZGlzdHJvPT0nbXVsdGljb3VudHJ5JyxdKQoKIyBXaGVyZSBhcmUgdGhlIFNpbmdsZXRvbnMKU2luZ2xldG9uLmNvdW50cnkuY291bnRzW1NpbmdsZXRvbi5jb3VudHJ5LmNvdW50cyRwZXIuY291bnRyeSE9MCxdCgojIFdoZXJlIGFyZSB0aGUgcHJpdmF0ZSBsaW5lYWdlcz8KUHJpdmF0ZS5jb3VudHJ5LmxvY2F0aW9uLmNvdW50c1tQcml2YXRlLmNvdW50cnkubG9jYXRpb24uY291bnRzJHBlci5jb3VudHJ5IT0wLF0KCmBgYAoKCgoKCiMgUGFpcndpc2UgU05QIGFuYWx5c2VzCgpgYGB7cn0KIyBpbXBvcnQgbXVsdGlwbGUgc2VxdWVuY2UgYWxpZ25tZW50ClRQQS5XR1MuYWxpZ25tZW50LmRhdGEgPC0gcGFpcnNucDo6aW1wb3J0X2Zhc3RhX3NwYXJzZShUUEEuTVNBLlNOUHMuYWxuLmZpbGUpCgojIHJ1biBwYWlyc25wClRQQS5XR1MuYWxpZ25tZW50LmRhdGEuZGlzdCA8LSBwYWlyc25wOjpzbnBfZGlzdChUUEEuV0dTLmFsaWdubWVudC5kYXRhKQpUUEEuV0dTLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdCA8LSByZXNoYXBlMjo6bWVsdChUUEEuV0dTLmFsaWdubWVudC5kYXRhLmRpc3QpCmNvbG5hbWVzKFRQQS5XR1MuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0KSA8LSBjKCJUYXhhMSIsICJUYXhhMiIsICJEaXN0YW5jZSIpCgojIEJyaW5nIGluIGFuZCBtZXJnZSBtZXRhZGF0YQpUUEEubWV0YTEuMi5wYWlyd2lzZS50MSA8LSBUUEEubWV0YTEuMi5waW5lY29uZVssYygiQ2xlYW5lZF9mYXN0cV9pZCIsIlNhbXBsZV9OYW1lIiwiU2FtcGxlX1llYXIiLCJHZW9fQ291bnRyeSIsIkNvbnRpbmVudCIsIlRQQS5waW5lY29uZS5tYWpvciIsIlRQQS5waW5lY29uZS5zdWJsaW5lYWdlIiwgIlRQQV9MaW5lYWdlIildCmNvbG5hbWVzKFRQQS5tZXRhMS4yLnBhaXJ3aXNlLnQxKSA8LSBwYXN0ZTAoY29sbmFtZXMoVFBBLm1ldGExLjIucGFpcndpc2UudDEpLCIudDEiKQpjb2xuYW1lcyhUUEEubWV0YTEuMi5wYWlyd2lzZS50MSlbMl0gPC0gIlRheGExIgpUUEEubWV0YTEuMi5wYWlyd2lzZS50MiA8LSBUUEEubWV0YTEuMi5waW5lY29uZVssYygiQ2xlYW5lZF9mYXN0cV9pZCIsIlNhbXBsZV9OYW1lIiwiU2FtcGxlX1llYXIiLCJHZW9fQ291bnRyeSIsIkNvbnRpbmVudCIsIlRQQS5waW5lY29uZS5tYWpvciIsIlRQQS5waW5lY29uZS5zdWJsaW5lYWdlIiwgIlRQQV9MaW5lYWdlIildCmNvbG5hbWVzKFRQQS5tZXRhMS4yLnBhaXJ3aXNlLnQyKSA8LSBwYXN0ZTAoY29sbmFtZXMoVFBBLm1ldGExLjIucGFpcndpc2UudDIpLCIudDIiKQpjb2xuYW1lcyhUUEEubWV0YTEuMi5wYWlyd2lzZS50MilbMl0gPC0gIlRheGEyIgoKVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhIDwtIHBseXI6OmpvaW4oVFBBLldHUy5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQsVFBBLm1ldGExLjIucGFpcndpc2UudDEsIGJ5PSJUYXhhMSIsIHR5cGU9ImxlZnQiKSAKVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhIDwtIHBseXI6OmpvaW4oVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLFRQQS5tZXRhMS4yLnBhaXJ3aXNlLnQyLCBieT0iVGF4YTIiLCB0eXBlPSJsZWZ0IikKCmBgYAoKRGVmaW5lIGNvbXBhcmlzb25zCmBgYHtyfQojIFNhbWUgc2FtcGxlClRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSRzYW1lLnNhbXBsZSA8LSBpZmVsc2UoVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhJFRheGExPT1UUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEkVGF4YTIsInNhbWUiLCAiZGlmZmVyZW50IikKCiMgWWVhcnMgYmV0d2VlbiBzYW1wbGVzClRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSR5ZWFyLmRpc3RhbmNlIDwtIGFicyhhcy5udW1lcmljKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSRTYW1wbGVfWWVhci50MSkgLSBhcy5udW1lcmljKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSRTYW1wbGVfWWVhci50MikpCgojIFNhbWUgY291bnRyeQpUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEkc2FtZS5jb3VudHJ5IDwtIGlmZWxzZShUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEkR2VvX0NvdW50cnkudDEgPT0gVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhJEdlb19Db3VudHJ5LnQyLCAic2FtZSIsICJkaWZmZXJlbnQiKQoKIyBTYW1lIGNvbnRpbmVudApUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEkc2FtZS5jb250aW5lbnQgPC0gaWZlbHNlKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSRDb250aW5lbnQudDEgPT0gVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhJENvbnRpbmVudC50MiwgInNhbWUiLCAiZGlmZmVyZW50IikKCiMgU2FtZSBUUEEgTWFqb3IgTGluZWFnZQpUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEkc2FtZS5UUEEubWFqb3JsaW5lYWdlIDwtIGlmZWxzZShUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEkVFBBLnBpbmVjb25lLm1ham9yLnQxPT1UUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEkVFBBLnBpbmVjb25lLm1ham9yLnQyLCAic2FtZSIsICJkaWZmZXJlbnQiKQpUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEkc2FtZS5UUEEubWFqb3JsaW5lYWdlIDwtIHNhcHBseSgxOm5yb3coVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhKSwgZnVuY3Rpb24oeCkgaWZlbHNlKChUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEkVFBBLnBpbmVjb25lLm1ham9yLnQxW3hdPT0iMCIgfCBUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEkVFBBLnBpbmVjb25lLm1ham9yLnQyW3hdPT0iMCIpLE5BLFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSRzYW1lLlRQQS5tYWpvcmxpbmVhZ2VbeF0pKQoKIyBTYW1lIFRQQSBMaW5lYWdlIChjbGVhbmVkIHVwIGNsYXNzaWZpY2F0aW9ucykKVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhJHNhbWUuVFBBLkxpbmVhZ2UgPC0gaWZlbHNlKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSRUUEFfTGluZWFnZS50MT09VFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhJFRQQV9MaW5lYWdlLnQyLCAic2FtZSIsICJkaWZmZXJlbnQiKQpUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEkc2FtZS5UUEEuTGluZWFnZSA8LSBzYXBwbHkoMTpucm93KFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSksIGZ1bmN0aW9uKHgpIGlmZWxzZSgoVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhJFRQQV9MaW5lYWdlLnQxW3hdPT0iMCIgfCBUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEkVFBBX0xpbmVhZ2UudDJbeF09PSIwIiksTkEsVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhJHNhbWUuVFBBLkxpbmVhZ2VbeF0pKQoKCiMgU2FtZSBUUEEgc3VibGluZWFnZQpUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEkc2FtZS5UUEEuUGluZWNvbmUuY2x1c3RlciA8LSBpZmVsc2UoVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlLnQxPT1UUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEkVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UudDIsInNhbWUiLCAiZGlmZmVyZW50IikKVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhJHNhbWUuVFBBLlBpbmVjb25lLmNsdXN0ZXIgPC0gc2FwcGx5KDE6bnJvdyhUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEpLCBmdW5jdGlvbih4KSBpZmVsc2UoKChUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEkc2FtZS5zYW1wbGVbeF09PSJkaWZmZXJlbnQiICYgVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlLnQxW3hdPT0iU2luZ2xldG9uIikgfChUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEkc2FtZS5zYW1wbGVbeF09PSJkaWZmZXJlbnQiICYgVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlLnQyW3hdPT0iU2luZ2xldG9uIikpLCJkaWZmZXJlbnQiLFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSRzYW1lLlRQQS5QaW5lY29uZS5jbHVzdGVyW3hdKSkKCiMgQ291bnRyeSBDb21wYXJpc29ucyBsYWJlbApUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEkQ291bnRyeV9jb21iaW5hdGlvbnMgPC0gcGFzdGUwKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSRHZW9fQ291bnRyeS50MSwiX19fIixUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEkR2VvX0NvdW50cnkudDIpCgpgYGAKCgpEbyBzb21lIGFuYWx5c2lzIG9mIFNOUCBkaXN0YW5jZXMgd2l0aGluIGVhY2ggY291bnRyeQpgYGB7cn0KClRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSRHZW9fQ291bnRyeS50MSA8LSBmYWN0b3IoVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhJEdlb19Db3VudHJ5LnQxLCBsZXZlbHM9Y29udGluZW50YWwuY291bnRyeS5jb2xzLmJyZXcyJEdlb19Db3VudHJ5KQoKcC5wYWlyd2lzZS5zbnBzLndpdGhpbkNvdW50cnkgPC0gZ2dwbG90KFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YVsoVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhJHNhbWUuY291bnRyeT09InNhbWUiICYgVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhJHNhbWUuc2FtcGxlPT0iZGlmZmVyZW50IiksXSwgYWVzKEdlb19Db3VudHJ5LnQxLCBEaXN0YW5jZSwgY29sb3I9R2VvX0NvdW50cnkudDEpKSArCiAgZ2VvbV9zaW5hKGFscGhhPTAuMjUsIHNjYWxlPSd3aWR0aCcsIG1ldGhvZD0iZCIpICsKICB0aGVtZV9saWdodCgpICsKICB0aGVtZS50ZXh0LnNpemUgKyAKICAjdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAtNDUsIHZqdXN0ID0gMC41LCBoanVzdD0wLjEpKSArCiAgeC50aGVtZS5heGlzLnJvdGF0ZSArCiAgbGFicyh4PSJDb3VudHJ5Iix5PSJQYWlyd2lzZSBTTlBzIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lPSJDb3VudHJ5Iix2YWx1ZXM9Y29udGluZW50YWwuY291bnRyeS5jb2xzLmJyZXcyJGNvdW50cnkuY29sLCBicmVha3M9Y29udGluZW50YWwuY291bnRyeS5jb2xzLmJyZXcyJEdlb19Db3VudHJ5KSArCiAgdGhlbWUobGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjY1LCJsaW5lIiksbGVnZW5kLnBvc2l0aW9uPSdyaWdodCcpICsgCiAgZ2d0aXRsZSgiUGFpcndpc2UgU05QIGRpc3RyaWJ1dGlvbnMgYmV0d2VlbiBzYW1wbGVzIGZyb20gc2FtZSBjb3VudHJpZXMiKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkgKwogIE5VTEwKcC5wYWlyd2lzZS5zbnBzLndpdGhpbkNvdW50cnkKCmBgYAoKClNwbGl0IHVwIGJ5IE1ham9yIExpbmVhZ2UKYGBge3J9CiNUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGFbKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSRzYW1lLmNvdW50cnk9PSJzYW1lIiAmIFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSRzYW1lLnNhbXBsZT09ImRpZmZlcmVudCIgJiBUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEkc2FtZS5UUEFfTGluZWFnZT09InNhbWUiKSxdCgojIE1heCBwYWlyd2lzZSBkaXN0YW5jZSB3aXRoaW4gY291bnRyeSBhbmQgd2l0aGluIExpbmVhZ2VzCm1heChUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGFbKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSRzYW1lLmNvdW50cnk9PSJzYW1lIiAmIFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSRzYW1lLnNhbXBsZT09ImRpZmZlcmVudCIgJiBUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEkc2FtZS5UUEEubWFqb3JsaW5lYWdlPT0ic2FtZSIgJiBUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEkVFBBX0xpbmVhZ2UudDE9PSJTUzE0IiksIkRpc3RhbmNlIl0pCgptYXgoVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhWyhUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEkc2FtZS5jb3VudHJ5PT0ic2FtZSIgJiBUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEkc2FtZS5zYW1wbGU9PSJkaWZmZXJlbnQiICYgVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhJHNhbWUuVFBBLm1ham9ybGluZWFnZT09InNhbWUiICYgVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhJFRQQV9MaW5lYWdlLnQxPT0iTmljaG9scyIpLCJEaXN0YW5jZSJdKQoKcC5wYWlyd2lzZS5zbnBzLndpdGhpbkNvdW50cnkud2l0aGluLkxpbmVhZ2UgPC0gZ2dwbG90KFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YVsoVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhJHNhbWUuY291bnRyeT09InNhbWUiICYgVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhJHNhbWUuc2FtcGxlPT0iZGlmZmVyZW50IiAmIFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSRzYW1lLlRQQS5tYWpvcmxpbmVhZ2U9PSJzYW1lIiksXSwgYWVzKEdlb19Db3VudHJ5LnQxLCBEaXN0YW5jZSwgY29sb3I9R2VvX0NvdW50cnkudDEpKSArCiAgZ2VvbV9zaW5hKGFscGhhPTAuNSwgc2NhbGU9J3dpZHRoJywgbWV0aG9kPSJkIikgKwogIHRoZW1lX2xpZ2h0KCkgKwogIHRoZW1lLnRleHQuc2l6ZSArIAogIHgudGhlbWUuYXhpcy5yb3RhdGUgKwogIGxhYnMoeD0iQ291bnRyeSIseT0iUGFpcndpc2UgU05QcyIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZT0iQ291bnRyeSIsdmFsdWVzPWNvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MiRjb3VudHJ5LmNvbCwgYnJlYWtzPWNvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MiRHZW9fQ291bnRyeSkgKwogIHRoZW1lKGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC42NSwibGluZSIpLGxlZ2VuZC5wb3NpdGlvbj0ncmlnaHQnKSArIAogIGdndGl0bGUoIlBhaXJ3aXNlIFNOUCBkaXN0cmlidXRpb25zIGJldHdlZW4gc2FtcGxlcyBmcm9tIHNhbWUgY291bnRyaWVzIGJ5IGxpbmVhZ2UiKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkgKwogIGZhY2V0X2dyaWQoVFBBX0xpbmVhZ2UudDF+LikgKwogIHRoZW1lKHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0nd2hpdGUnLGxpbmV0eXBlPSJzb2xpZCIpLCBzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoY29sb3IgPSAiZ3JleTI1Iiwgc2l6ZT0xMCkpICsKICBOVUxMCnAucGFpcndpc2Uuc25wcy53aXRoaW5Db3VudHJ5LndpdGhpbi5MaW5lYWdlCgoKYGBgCgpEbyBhIGNvbWJpbmVkIHBsb3QgKGFsbCwgcGx1cyBieSBtYWpvciBsaW5lYWdlKQpgYGB7cn0KClRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5MaW5lYWdlQ291bnRyeUNvbWJpbmVkIDwtIFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YVsoVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhJHNhbWUuY291bnRyeT09InNhbWUiICYgVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhJHNhbWUuc2FtcGxlPT0iZGlmZmVyZW50IiAmIFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSRzYW1lLlRQQS5tYWpvcmxpbmVhZ2U9PSJzYW1lIiksYygiR2VvX0NvdW50cnkudDEiLCAiRGlzdGFuY2UiLCJUUEFfTGluZWFnZS50MSIpXQpUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuTGluZWFnZUNvdW50cnlDb21iaW5lZCRUUEFfTGluZWFnZSA8LSBUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuTGluZWFnZUNvdW50cnlDb21iaW5lZCRUUEFfTGluZWFnZS50MQoKVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLkxpbmVhZ2VDb3VudHJ5Q29tYmluZWQuMiA8LSBUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGFbKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSRzYW1lLmNvdW50cnk9PSJzYW1lIiAmIFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSRzYW1lLnNhbXBsZT09ImRpZmZlcmVudCIpLGMoIkdlb19Db3VudHJ5LnQxIiwgIkRpc3RhbmNlIiwiVFBBX0xpbmVhZ2UudDEiKV0KVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLkxpbmVhZ2VDb3VudHJ5Q29tYmluZWQuMiRUUEFfTGluZWFnZSA8LSAiQWxsIgoKClRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5MaW5lYWdlQ291bnRyeUNvbWJpbmVkIDwtIHJiaW5kKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5MaW5lYWdlQ291bnRyeUNvbWJpbmVkLCBUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuTGluZWFnZUNvdW50cnlDb21iaW5lZC4yKQoKcC5wYWlyd2lzZS5zbnBzLndpdGhpbkNvdW50cnkud2l0aGluLmFsbC5MaW5lYWdlIDwtIGdncGxvdChUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuTGluZWFnZUNvdW50cnlDb21iaW5lZCwgYWVzKEdlb19Db3VudHJ5LnQxLCBEaXN0YW5jZSwgY29sb3I9R2VvX0NvdW50cnkudDEpKSArCiAgZ2VvbV9zaW5hKGFscGhhPTAuNSwgc2NhbGU9J3dpZHRoJywgbWV0aG9kPSJkIikgKwogIHRoZW1lX2xpZ2h0KCkgKwogIHRoZW1lLnRleHQuc2l6ZSArIAogIHgudGhlbWUuYXhpcy5yb3RhdGUgKwogIGxhYnMoeD0iQ291bnRyeSIseT0iUGFpcndpc2UgU05QcyIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZT0iQ291bnRyeSIsdmFsdWVzPWNvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MiRjb3VudHJ5LmNvbCwgYnJlYWtzPWNvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MiRHZW9fQ291bnRyeSkgKwogIHRoZW1lKGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC42NSwibGluZSIpLGxlZ2VuZC5wb3NpdGlvbj0ncmlnaHQnKSArIAogIGdndGl0bGUoIlBhaXJ3aXNlIFNOUCBkaXN0cmlidXRpb25zIGFtb25nIHNhbXBsZXMgd2l0aGluIHRoZSBzYW1lIGNvdW50cnkiKSArCiAgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKSArCiAgZmFjZXRfZ3JpZChUUEFfTGluZWFnZX4uKSArCiAgdGhlbWUoc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPSd3aGl0ZScsbGluZXR5cGU9InNvbGlkIiksIHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJncmV5MjUiLCBzaXplPTEwKSkgKwogIE5VTEwKcC5wYWlyd2lzZS5zbnBzLndpdGhpbkNvdW50cnkud2l0aGluLmFsbC5MaW5lYWdlCgpgYGAKCgoKCkxvb2sgYXQgcGFpcndpc2UgZGlzdGFuY2VzIGJldHdlZW4gY291bnRyaWVzIChlLmcuIG1pbmltdW0gcGFpcndpc2UgZGlzdGFuY2UpCmBgYHtyfQpUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuYmV0d2Vlbi5jb3VudHJpZXMgPC0gVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhW1RQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSRzYW1lLmNvdW50cnk9PSJkaWZmZXJlbnQiLF0KClRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5iZXR3ZWVuLmNvdW50cmllcy5taW5kaXN0IDwtIFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5iZXR3ZWVuLmNvdW50cmllcyAlPiUgCiAgZHBseXI6Omdyb3VwX2J5KENvdW50cnlfY29tYmluYXRpb25zKSAlPiUKICBzdW1tYXJpc2UobWluLmRpc3Q9bWluKERpc3RhbmNlKSkKVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLmJldHdlZW4uY291bnRyaWVzLm1pbmRpc3QkVGF4YTEgPC0gZ3N1YigiXFxfXFxfXFxfLiskIiwiIixUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuYmV0d2Vlbi5jb3VudHJpZXMubWluZGlzdCRDb3VudHJ5X2NvbWJpbmF0aW9ucywgcGVybD1UKQpUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuYmV0d2Vlbi5jb3VudHJpZXMubWluZGlzdCRUYXhhMiA8LSBnc3ViKCJeLitcXF9cXF9cXF8iLCIiLFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5iZXR3ZWVuLmNvdW50cmllcy5taW5kaXN0JENvdW50cnlfY29tYmluYXRpb25zLCBwZXJsPVQpCgpUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuYmV0d2Vlbi5jb3VudHJpZXMubWluZGlzdCRsb2cxMC5taW5kaXN0IDwtIGxvZzEwKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5iZXR3ZWVuLmNvdW50cmllcy5taW5kaXN0JG1pbi5kaXN0KQoKVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLmJldHdlZW4uY291bnRyaWVzLm1pbmRpc3QkbG9nMi5taW5kaXN0IDwtIGxvZzIoVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLmJldHdlZW4uY291bnRyaWVzLm1pbmRpc3QkbWluLmRpc3QpCgpUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuYmV0d2Vlbi5jb3VudHJpZXMubWluZGlzdCRUYXhhMSA8LSBmYWN0b3IoVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLmJldHdlZW4uY291bnRyaWVzLm1pbmRpc3QkVGF4YTEsIGxldmVscz1jb250aW5lbnRhbC5jb3VudHJ5LmNvbHMuYnJldzIkR2VvX0NvdW50cnkpClRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5iZXR3ZWVuLmNvdW50cmllcy5taW5kaXN0JFRheGEyIDwtIGZhY3RvcihUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuYmV0d2Vlbi5jb3VudHJpZXMubWluZGlzdCRUYXhhMiwgbGV2ZWxzPWNvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MiRHZW9fQ291bnRyeSkKCgojV0dTLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLmJldHdlZW4uY291bnRyaWVzLm1pbmRpc3QubWF0cml4IDwtIGRjYXN0KFdHUy5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5iZXR3ZWVuLmNvdW50cmllcy5taW5kaXN0WyxjKDMsNCwyKV0sIHRheGExfnRheGEyKQoKdGF4YTEucHdpc2UuY291bnRyeS5jb2xzIDwtIHVuaXF1ZShUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuYmV0d2Vlbi5jb3VudHJpZXMubWluZGlzdCRUYXhhMSkKCgpwLmNvdW50cnkubWluc25wLmhlYXRtYXAgPC0gZ2dwbG90KFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5iZXR3ZWVuLmNvdW50cmllcy5taW5kaXN0LCBhZXMoVGF4YTEsIFRheGEyLCBmaWxsPW1pbi5kaXN0KSkgKwogIGdlb21fdGlsZShjb2xvcj0id2hpdGUiKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9InllbGxvdyIsaGlnaD0icmVkIiwgdHJhbnM9ImxvZzIiLG5hbWU9Ik1pbmltdW0gUGFpcndpc2UgU05QcyIpICsgCiAgI3RoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWVfbGlnaHQoKSArCiAgdGhlbWUudGV4dC5zaXplICsgCiAgc2NhbGVfeF9kaXNjcmV0ZShwb3NpdGlvbiA9ICd0b3AnKSArCiAgI3RoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT05MCxoanVzdD0wKSwgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICMgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpICsKICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9OTAsdmp1c3Q9MSxoanVzdD0wKSwgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IG1pbi5kaXN0KSwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMi41KSArCiAgI3RoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG91cj1kYXRhLmZyYW1lKGNvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MilbY29udGluZW50YWwuY291bnRyeS5jb2xzLmJyZXcyJEdlb19Db3VudHJ5IT0iQmVsZ2l1bSIsImNvdW50cnkuY29sIl0pLCBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChjb2xvdXI9ZGF0YS5mcmFtZShjb250aW5lbnRhbC5jb3VudHJ5LmNvbHMuYnJldzIpW2NvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MiRHZW9fQ291bnRyeSE9IkJlbGdpdW0iLCJjb3VudHJ5LmNvbCJdKSkgKwogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGNvbG91cj1kYXRhLmZyYW1lKGNvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MilbY29udGluZW50YWwuY291bnRyeS5jb2xzLmJyZXcyJEdlb19Db3VudHJ5IT0iQmVsZ2l1bSIsImNvdW50cnkuY29sIl0pKSAgKwogIHRoZW1lKGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC42NSwibGluZSIpLCBsZWdlbmQucG9zaXRpb249J2xlZnQnKSArCiAgI2dndGl0bGUoIk1pbmltdW0gUGFpcndpc2UgU05QcyBiZXR3ZWVuIHNhbXBsZXMgZnJvbSBkaWZmZXJlbnQgY291bnRyaWVzIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgbGFicyh5PSJDb3VudHJ5IikgKwogIE5VTEwKCgoKcC5jb3VudHJ5Lm1pbnNucC5oZWF0bWFwCmBgYAoKU2FtcGxlcyBwZXIgY291bnRyeSAoaGlnaCBxdWFsaXR5IGdlbm9tZXMpIC0gbmVlZGVkIHRvIGdpdmUgc29tZSBjb250ZXh0IHRvIHRoZSBoZWF0bWFwIHBsb3QKYGBge3J9ClRQQS5waW5lY29uZS5nZW5vbWUuY291bnRzIDwtIFRQQS5tZXRhMS4yLnBpbmVjb25lICU+JSBkcGx5cjo6Z3JvdXBfYnkoR2VvX0NvdW50cnkpICU+JQogIGRwbHlyOjpzdW1tYXJpc2UoVG90YWxfc2FtcGxlcz1uKCkpClRQQS5waW5lY29uZS5nZW5vbWUuY291bnRzJEdlb19Db3VudHJ5IDwtIGZhY3RvcihUUEEucGluZWNvbmUuZ2Vub21lLmNvdW50cyRHZW9fQ291bnRyeSwgbGV2ZWxzPWNvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MiRHZW9fQ291bnRyeSkKCnAuaHEuY291bnRyeS5oYmFycGxvdCA8LSBnZ3Bsb3QoVFBBLnBpbmVjb25lLmdlbm9tZS5jb3VudHMsIGFlcyhUb3RhbF9zYW1wbGVzLEdlb19Db3VudHJ5LGZpbGw9R2VvX0NvdW50cnkpKSArCiAgZ2VvbV9iYXJoKHN0YXQ9ImlkZW50aXR5IiwgcG9zaXRpb249InN0YWNrIiwgd2lkdGg9MC43NSkgKwogIGdlb21fdGV4dChkYXRhPVRQQS5waW5lY29uZS5nZW5vbWUuY291bnRzLCBhZXMoKFRvdGFsX3NhbXBsZXMrMjUpLCBHZW9fQ291bnRyeSwgbGFiZWw9VG90YWxfc2FtcGxlcyksIHNpemU9Mi41LCBpbmhlcml0LmFlcyA9IEYpICsKICAjdGhlbWVfY2xhc3NpYygpICsgCiAgdGhlbWVfbGlnaHQoKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDAsMTAwLDIwMCwzMDApKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW09YygwLDI3NSkpICsKICB0aGVtZS50ZXh0LnNpemUgKyB0aGVtZShsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNjUsImxpbmUiKSxsZWdlbmQucG9zaXRpb249J25vbmUnKSArCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZT0iQ291bnRyeSIsdmFsdWVzPWNvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MiRjb3VudHJ5LmNvbCwgYnJlYWtzPWNvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MiRHZW9fQ291bnRyeSkgKwogIGxhYnMoeT0iQ291bnRyeSIsIHg9IlNhbXBsZSBDb3VudCIpICsKICAjdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkgCiAgTlVMTAojcC5ocS5jb3VudHJ5LmhiYXJwbG90CgoKcC5ocS5jb3VudHJ5LmJhcnBsb3QgPC0gZ2dwbG90KFRQQS5waW5lY29uZS5nZW5vbWUuY291bnRzLCBhZXMoR2VvX0NvdW50cnksIFRvdGFsX3NhbXBsZXMsZmlsbD1HZW9fQ291bnRyeSkpICsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIHBvc2l0aW9uPSJzdGFjayIsIHdpZHRoPTAuNzUpICsKICBnZW9tX3RleHQoZGF0YT1UUEEucGluZWNvbmUuZ2Vub21lLmNvdW50cywgYWVzKEdlb19Db3VudHJ5LCAoVG90YWxfc2FtcGxlcysyNSksIGxhYmVsPVRvdGFsX3NhbXBsZXMpLCBzaXplPTIuNSwgaW5oZXJpdC5hZXMgPSBGKSArCiAgdGhlbWVfbGlnaHQoKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1jKDAsMTAwLDIwMCwzMDApKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDI3NSkpICsKICB0aGVtZS50ZXh0LnNpemUgKyB0aGVtZShsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNjUsImxpbmUiKSxsZWdlbmQucG9zaXRpb249J25vbmUnKSArCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZT0iQ291bnRyeSIsdmFsdWVzPWNvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MiRjb3VudHJ5LmNvbCwgYnJlYWtzPWNvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MiRHZW9fQ291bnRyeSkgKwogIGxhYnMoeD0iQ291bnRyeSIsIHk9IlNhbXBsZSBDb3VudCIpICsKICB4LnRoZW1lLmF4aXMucm90YXRlICsKICBOVUxMCiNwLmhxLmNvdW50cnkuaGJhcnBsb3QKCmBgYAoKCnBsb3QgdG9nZXRoZXIKYGBge3J9CnAuY291bnRyeS5taW5zbnAuaGVhdG1hcC5jb3VudHMgPC0gcGxvdF9ncmlkKHAuY291bnRyeS5taW5zbnAuaGVhdG1hcCwgcC5ocS5jb3VudHJ5LmhiYXJwbG90ICsgeS50aGVtZS5zdHJpcCwgYWxpZ249VCwgbmNvbD0yLCByZWxfd2lkdGhzPWMoNSwxKSkKcC5jb3VudHJ5Lm1pbnNucC5oZWF0bWFwLmNvdW50cyAKYGBgCgoKUGxvdCBzaW5hIG9mIHdpdGhpbi1jb3VudHJ5IFNOUHMgYWxvbmdzaWRlIGhlYXRtYXAgb2YgbWluLVNOUHMgYmV0d2VlbiBjb3VudHJpZXMKCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9NSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbXVsdGljb3VudHJ5LnBhaXJ3aXNlLnNucHMuZ3JpZCA8LSBwbG90X2dyaWQocC5wYWlyd2lzZS5zbnBzLndpdGhpbkNvdW50cnkscC5jb3VudHJ5Lm1pbnNucC5oZWF0bWFwLmNvdW50cywgbmNvbD0yLCByZWxfd2lkdGhzPWMoMiwzKSwgbGFiZWxzPWMoJ0QnLCdFJyksIGxhYmVsX3NpemU9MTEpCm11bHRpY291bnRyeS5wYWlyd2lzZS5zbnBzLmdyaWQKYGBgCgoKR2V0IGNvbWJpbmF0aW9uIGRldGFpbHMgZm9yIGFsbCB6ZXJvIHBhaXJpbmdzCmBgYHtyfQojIGVuc3VyZSBhbGwgcG9zc2libGUgY29tYm9zIGFyZSBpbmNsdWRlZCBieSAyLXNpZGluZwpUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuYmV0d2Vlbi5jb3VudHJpZXMubWluZGlzdC5jb21iaW5hdGlvbnMgPC0gcmJpbmQoZGF0YS5mcmFtZShtaW4uZGlzdD1UUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuYmV0d2Vlbi5jb3VudHJpZXMubWluZGlzdCRtaW4uZGlzdCwgdGF4YTE9VFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLmJldHdlZW4uY291bnRyaWVzLm1pbmRpc3QkVGF4YTEsdGF4YTI9VFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLmJldHdlZW4uY291bnRyaWVzLm1pbmRpc3QkVGF4YTIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKSxkYXRhLmZyYW1lKG1pbi5kaXN0PVRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5iZXR3ZWVuLmNvdW50cmllcy5taW5kaXN0JG1pbi5kaXN0LCB0YXhhMT1UUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuYmV0d2Vlbi5jb3VudHJpZXMubWluZGlzdCRUYXhhMix0YXhhMj1UUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuYmV0d2Vlbi5jb3VudHJpZXMubWluZGlzdCRUYXhhMSwgc3RyaW5nc0FzRmFjdG9ycyA9IEYpKSAKVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLmJldHdlZW4uY291bnRyaWVzLm1pbmRpc3QuY29tYmluYXRpb25zIDwtIHVuaXF1ZShUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuYmV0d2Vlbi5jb3VudHJpZXMubWluZGlzdC5jb21iaW5hdGlvbnMpCgpUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuYmV0d2Vlbi5jb3VudHJpZXMubWluZGlzdC5jb21iaW5hdGlvbnMuemVyb3MgPC0gVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLmJldHdlZW4uY291bnRyaWVzLm1pbmRpc3QuY29tYmluYXRpb25zW1RQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5iZXR3ZWVuLmNvdW50cmllcy5taW5kaXN0LmNvbWJpbmF0aW9ucyRtaW4uZGlzdD09MCxdCgpUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuYmV0d2Vlbi5jb3VudHJpZXMubWluZGlzdC5jb21iaW5hdGlvbnMuemVyb3MuY29tYm9zIDwtIFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5iZXR3ZWVuLmNvdW50cmllcy5taW5kaXN0LmNvbWJpbmF0aW9ucy56ZXJvcyAlPiUgZHBseXI6Omdyb3VwX2J5KHRheGExLCB0YXhhMikgJT4lIGRwbHlyOjpzdW1tYXJpc2UoY291bnQ9bigpKQoKbnJvdyhUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuYmV0d2Vlbi5jb3VudHJpZXMubWluZGlzdC5jb21iaW5hdGlvbnMuemVyb3MuY29tYm9zKS8yClRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5iZXR3ZWVuLmNvdW50cmllcy5taW5kaXN0LmNvbWJpbmF0aW9ucy56ZXJvcy5jb21ib3MKCmBgYAoKCgpHZXQgc3BlY2lmaWMgcGFpcndpc2Ugc3RhdHMgZm9yIFVLIGFuZCBDYW5hZGEKYGBge3J9CgpUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhIDwtIChUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGFbKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSRDb3VudHJ5X2NvbWJpbmF0aW9ucz09IlVLX19fQ2FuYWRhIiB8IFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSRDb3VudHJ5X2NvbWJpbmF0aW9ucz09IkNhbmFkYV9fX1VLIiksYygiVGF4YTEiLCJUYXhhMiIsIkRpc3RhbmNlIiwgIkNvdW50cnlfY29tYmluYXRpb25zIiwieWVhci5kaXN0YW5jZSIpXSkKCiMgTnVtYmVyIG9mIGNvbXBhcmlzb25zCm5yb3coVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLlVLLkNhbmFkYVtUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhJERpc3RhbmNlPT0wLF0pCgoKQ2FuYWRhLlVLLnplcm8uY29tcGFyaXNvbi5zYW1wbGVzIDwtIGFzLmNoYXJhY3Rlcih1bmlxdWUoVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLlVLLkNhbmFkYVtUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhJERpc3RhbmNlPT0wLCJUYXhhMSJdKSkKQ2FuYWRhLlVLLnplcm8uY29tcGFyaXNvbi5zYW1wbGVzIDwtIHVuaXF1ZShjKENhbmFkYS5VSy56ZXJvLmNvbXBhcmlzb24uc2FtcGxlcyxhcy5jaGFyYWN0ZXIodW5pcXVlKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5VSy5DYW5hZGFbVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLlVLLkNhbmFkYSREaXN0YW5jZT09MCwiVGF4YTIiXSkpKSkKCkNhbmFkYS5VSy56ZXJvLmNvbXBhcmlzb24uc2FtcGxlcyA8LSBkYXRhLmZyYW1lKFNhbXBsZV9OYW1lPUNhbmFkYS5VSy56ZXJvLmNvbXBhcmlzb24uc2FtcGxlcyxzdHJpbmdzQXNGYWN0b3JzID0gRikKQ2FuYWRhLlVLLnplcm8uY29tcGFyaXNvbi5zYW1wbGVzIDwtIHBseXI6OmpvaW4oQ2FuYWRhLlVLLnplcm8uY29tcGFyaXNvbi5zYW1wbGVzLFRQQS5tZXRhMS4yLCBieT0iU2FtcGxlX05hbWUiLCB0eXBlPSJsZWZ0IikKCm5yb3coQ2FuYWRhLlVLLnplcm8uY29tcGFyaXNvbi5zYW1wbGVzKQpucm93KENhbmFkYS5VSy56ZXJvLmNvbXBhcmlzb24uc2FtcGxlc1tDYW5hZGEuVUsuemVyby5jb21wYXJpc29uLnNhbXBsZXMkR2VvX0NvdW50cnk9PSJVSyIsXSkKbnJvdyhDYW5hZGEuVUsuemVyby5jb21wYXJpc29uLnNhbXBsZXNbQ2FuYWRhLlVLLnplcm8uY29tcGFyaXNvbi5zYW1wbGVzJEdlb19Db3VudHJ5PT0iQ2FuYWRhIixdKQoKCiMgTG9vayBhdCB0ZW1wb3JhbCBkaXN0YW5jZSB3aXRoaW4gemVyby1TTlAgY29tcGFyaXNvbnMgYmV0d2VlbiBjb3VudHJpZXMKc29ydCh1bmlxdWUoVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLlVLLkNhbmFkYVtUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhJERpc3RhbmNlPT0wLCJ5ZWFyLmRpc3RhbmNlIl0pKQoKIyBJZGVudGlmeSBzYW1wbGVzIGludm92bGVkIGluIGEgMCBTTlAgY29tcGFyaXNvbiBhbmQgYXJlIDE0IHllYXJzIGFwYXJ0CnVuaXF1ZShhcy52ZWN0b3IoYXMubWF0cml4KFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5VSy5DYW5hZGFbKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5VSy5DYW5hZGEkRGlzdGFuY2U9PTAgJiBUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhJHllYXIuZGlzdGFuY2U9PTE0KSxjKCJUYXhhMSIsIlRheGEyIildKSkpCgpUUEEubWV0YTEuMi5waW5lY29uZVtUUEEubWV0YTEuMi5waW5lY29uZSRTYW1wbGVfTmFtZSAlaW4lIGMoIlRQQV9VS0JJUjA0OSIsICJUUEFfVUtCSVIwMzAiLCAiVFBBX0JDQzAzMCIsICJUUEFfQkNDMDMyIiwgIlRQQV9VS01BTjAyNyIsICJUUEFfVUtMRUUwMDQiKSxdCgpUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGFbKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSRUYXhhMSAlaW4lIGMoIlRQQV9CQ0MwMzAiLCJUUEFfQkNDMDMyIikgJiBUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEkVGF4YTIgJWluJSBjKCJUUEFfQkNDMDMwIiwiVFBBX0JDQzAzMiIpKSxdCiMiVFBBX0JDQzAzMCIsICJUUEFfQkNDMDMyIiAKCgptaW4oQ2FuYWRhLlVLLnplcm8uY29tcGFyaXNvbi5zYW1wbGVzWywiU2FtcGxlX1llYXIiXSkKbWF4KENhbmFkYS5VSy56ZXJvLmNvbXBhcmlzb24uc2FtcGxlc1ssIlNhbXBsZV9ZZWFyIl0pCgpUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEKYGBgCgpNYWtlIGEgcGxvdCBsb29raW5nIGF0IHBhaXJ3aXNlIGRpc3RhbmNlcyBpbiBVSyBhbmQgQ2FuYWRhCmBgYHtyfQpUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhLmZ1bGxtZXRhIDwtIChUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGFbKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSRDb3VudHJ5X2NvbWJpbmF0aW9ucz09IkNhbmFkYV9fX1VLIiB8IFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSRDb3VudHJ5X2NvbWJpbmF0aW9ucz09IkNhbmFkYV9fX0NhbmFkYSIgfCAgVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhJENvdW50cnlfY29tYmluYXRpb25zPT0iVUtfX19VSyIpLF0pCgpUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhLmZ1bGxtZXRhIDwtIFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5VSy5DYW5hZGEuZnVsbG1ldGFbVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLlVLLkNhbmFkYS5mdWxsbWV0YSRzYW1lLnNhbXBsZT09ImRpZmZlcmVudCIsXQoKVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLlVLLkNhbmFkYS5mdWxsbWV0YSRDb3VudHJ5X2NvbWJpbmF0aW9uczIgPC0gZ3N1YigiVUtfX19VSyIsIkVuZ2xhbmQiLGdzdWIoIkNhbmFkYV9fX0NhbmFkYSIsIkJyaXRpc2ggQ29sdW1iaWEiLGdzdWIoIkNhbmFkYV9fX1VLIiwiQnJpdGlzaCBDb2x1bWJpYSB2LnMuIEVuZ2xhbmQiLFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5VSy5DYW5hZGEuZnVsbG1ldGEkQ291bnRyeV9jb21iaW5hdGlvbnMpKSkKCgojIGRvIGRpc3RyaWJ1dGlvbnMgcGxvdHMgb24gUFcgU05QcyBmb3IgY291bnRyeSBjb21wYXJpc29ucwpwLlVLLmNhbmFkYS5wd1NOUHMuc2luYSA8LSBnZ3Bsb3QoVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLlVLLkNhbmFkYS5mdWxsbWV0YSwgYWVzKENvdW50cnlfY29tYmluYXRpb25zMiwgRGlzdGFuY2UpKSArCiAgZ2VvbV9zaW5hKGFscGhhPTAuMSxzaXplPTEsIGFlcyhjb2xvcj1Db3VudHJ5X2NvbWJpbmF0aW9uczIpKSArIAogICNnZW9tX2JveHBsb3QoYWxwaGE9MC4wMSwgb3V0bGllci5zaGFwZSA9IE5BLCB3aWR0aD0wLjI1KSArCiAgdGhlbWVfbGlnaHQoKSArCiAgdGhlbWUudGV4dC5zaXplICsgCiAgI3NjYWxlX3lfbG9nMTAoKSArCiAgbGFicyh4PSJDb3VudHJ5IENvbWJpbmF0aW9uIix5PSJQYWlyd2lzZSBTTlBzIikgKwogICNzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcz1jKCIjNzRDNDc2IiwgImN5YW4zIiwgIiMwODQ1OTQiKSkgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzPWMoIiM3NEM0NzYiLCAiZ3JleTUwIiwgIiMwODQ1OTQiKSkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb249J25vbmUnKSArCiAgZ2d0aXRsZSgiUGFpcndpc2UgU05QcyB3aXRoaW4gYW5kIGJldHdlZW4gQnJpdGlzaCBDb2x1bWJpYSAoQ2FuYWRhKSBhbmQgRW5nbGFuZCAoVUspIikgKwogIE5VTEwKcC5VSy5jYW5hZGEucHdTTlBzLnNpbmEKCiMgRG8gZGlzdHJpYnV0aW9ucyBvZiBwd1NOUHMgdi5zLiB0aW1lcG9pbnRzCnAuVUsuY2FuYWRhLnB3U05Qcy52cy5UaW1lLnBvaW50cyA8LSBnZ3Bsb3QoVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLlVLLkNhbmFkYS5mdWxsbWV0YSwgYWVzKHllYXIuZGlzdGFuY2UsRGlzdGFuY2UpKSArCiAgZ2VvbV9wb2ludChzaXplPTEsIGFscGhhPTAuMSkgKwogIGdlb21fZGVuc2l0eV8yZCgpICsKICB0aGVtZV9saWdodCgpICsKICBmYWNldF9ncmlkKC5+Q291bnRyeV9jb21iaW5hdGlvbnMyKSArIAogIHNjYWxlX3lfbG9nMTAoKSArCiAgbGFicyh5PSJQYWlyd2lzZSBTTlAgZGlzdGFuY2UgKGxvZzEwIHNjYWxlKSIsIHg9IlBhaXJ3aXNlIHRpbWUgZGlzdGFuY2UgKHllYXJzKSIpICsKICB0aGVtZS50ZXh0LnNpemUgKwogIHRoZW1lKHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0nd2hpdGUnLGxpbmV0eXBlPSJzb2xpZCIpLCBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3IgPSAiZ3JleTI1Iiwgc2l6ZT0xMCkpCiNwLlVLLmNhbmFkYS5wd1NOUHMudnMuVGltZS5wb2ludHMgCgojIEJyZWFrZG93biBwYWlyd2lzZSBTTlAvdGltZSBkaXN0YW5jZXMgYnkgc3VibGluZWFnZQpUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhLmZ1bGxtZXRhJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlLnQxIDwtIGZhY3RvcihUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhLmZ1bGxtZXRhJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlLnQxLCBsZXZlbHM9c3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2UpCnAuVUsuY2FuYWRhLnB3U05Qcy52cy5UaW1lLnBvaW50cy5zdWJsaW5lYWdlLmJyZWFrZG93biA8LSBnZ3Bsb3QoVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLlVLLkNhbmFkYS5mdWxsbWV0YVtUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhLmZ1bGxtZXRhJHNhbWUuVFBBLlBpbmVjb25lLmNsdXN0ZXI9PSJzYW1lIixdLCBhZXMoeWVhci5kaXN0YW5jZSxEaXN0YW5jZSwgY29sb3I9VFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UudDEpKSArCiAgZ2VvbV9wb2ludChzaXplPTIsIGFscGhhPTAuMjUpICsKICBnZW9tX2RlbnNpdHlfMmQoY29sb3I9ImJsYWNrIiwgYWxwaGE9MC41KSArCiAgdGhlbWVfbGlnaHQoKSArCiAgZmFjZXRfZ3JpZChUUEEucGluZWNvbmUuc3VibGluZWFnZS50MX5Db3VudHJ5X2NvbWJpbmF0aW9uczIpICsgCiAgI3NjYWxlX3lfbG9nMTAoKSArCiAgbGFicyh5PSJQYWlyd2lzZSBTTlAgZGlzdGFuY2UgKGxvZzEwIHNjYWxlKSIsIHg9IlBhaXJ3aXNlIHRpbWUgZGlzdGFuY2UgKHllYXJzKSIpICsKICB0aGVtZS50ZXh0LnNpemUgKwogIHRoZW1lKHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0nd2hpdGUnLGxpbmV0eXBlPSJzb2xpZCIpLCBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3IgPSAiZ3JleTI1Iiwgc2l6ZT0xMCksc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gImdyZXkyNSIsIHNpemU9MTApKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWU9IlN1YmxpbmVhZ2UiLHZhbHVlcz1zdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZS5jb2xzLCBicmVha3M9c3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2UpICsgCiAgTlVMTApwLlVLLmNhbmFkYS5wd1NOUHMudnMuVGltZS5wb2ludHMuc3VibGluZWFnZS5icmVha2Rvd24KCgoKCgoKIyBkbyBwd1NOUHMgdi5zLiB0aW1lcG9pbnRzIHVzaW5nIGEgaGV4cGxvdCB0byByZWR1Y2Ugb3ZlcnBsb3R0aW5nCnAuVUsuY2FuYWRhLnB3U05Qcy52cy5UaW1lLmhleCA8LSBnZ3Bsb3QoVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLlVLLkNhbmFkYS5mdWxsbWV0YSwgYWVzKHllYXIuZGlzdGFuY2UsRGlzdGFuY2UpKSArCiAgc3RhdF9iaW5faGV4KGNvbG91cj0id2hpdGUiLCBuYS5ybT1UUlVFLCBiaW5zID0gMjApICsKICBzY2FsZV9maWxsX2dyYWRpZW50bihjb2xvdXJzPWMoInB1cnBsZSIsImdyZWVuIiksIAogICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiQ29tcGFyaXNvbiBGcmVxdWVuY3kiLCBicmVha3M9YygxLDMwLDEwMDApLAogICAgICAgICAgICAgICAgICAgICAgIG5hLnZhbHVlPU5BLCB0cmFucz0ibG9nMTAiKSArIAogIGZhY2V0X2dyaWQoLn5Db3VudHJ5X2NvbWJpbmF0aW9uczIpICsgCiAgdGhlbWVfbGlnaHQoKSArCiAgbGFicyh5PSJQYWlyd2lzZSBTTlAgZGlzdGFuY2UiLCB4PSJQYWlyd2lzZSB0aW1lIGRpc3RhbmNlICh5ZWFycykiKSArCiAgdGhlbWUudGV4dC5zaXplICsgdGhlbWUobGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjc1LCJsaW5lIikpICsKICB0aGVtZShzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9J3doaXRlJyxsaW5ldHlwZT0ic29saWQiKSwgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gImdyZXkyNSIsIHNpemU9MTApKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iKSArCiAgZ2d0aXRsZSgiUGFpcndpc2UgU05QcyBhbmQgWWVhcnMgd2l0aGluIGFuZCBiZXR3ZWVuIEJyaXRpc2ggQ29sdW1iaWEgKENhbmFkYSkgYW5kIEVuZ2xhbmQgKFVLKSIpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKQojcC5VSy5jYW5hZGEucHdTTlBzLnZzLlRpbWUuaGV4CgoKCgojIGRvIHB3U05QcyB2LnMuIHRpbWVwb2ludHMgdXNpbmcgYSBoZXhwbG90IHRvIHJlZHVjZSBvdmVycGxvdHRpbmcgKGJ5IHN1YmxpbmVhZ2UpClRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5VSy5DYW5hZGEuZnVsbG1ldGEud2l0aGluLnN1YmxpbmVhZ2UgPC0gVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLlVLLkNhbmFkYS5mdWxsbWV0YVtUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhLmZ1bGxtZXRhJHNhbWUuVFBBLlBpbmVjb25lLmNsdXN0ZXI9PSJzYW1lIixdCgpwLlVLLmNhbmFkYS5wd1NOUHMudnMuVGltZS5oZXguc3VibGluZWFnZS5icmVha2Rvd24gPC0gZ2dwbG90KFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5VSy5DYW5hZGEuZnVsbG1ldGEud2l0aGluLnN1YmxpbmVhZ2UsIGFlcyh5ZWFyLmRpc3RhbmNlLERpc3RhbmNlKSkgKwogIHN0YXRfYmluX2hleChjb2xvdXI9IndoaXRlIiwgbmEucm09VFJVRSwgYmlucyA9IDE1KSArCiAgI2dlb21fZGVuc2l0eV8yZF9maWxsZWQoKSArCiAgI2dlb21fZGVuc2l0eV8yZF9maWxsZWQoKSArIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGU9IlB1UmQiKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudG4oY29sb3Vycz1jKCJwdXJwbGUiLCJncmVlbiIpLCAKICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIkNvbXBhcmlzb24gRnJlcXVlbmN5IiwgYnJlYWtzPWMoMSwzMCwxMDAwKSwKICAgICAgICAgICAgICAgICAgICAgICBuYS52YWx1ZT1OQSwgdHJhbnM9ImxvZzEwIikgKyAKICAjZ2VvbV9wb2ludChhbHBoYT0wLjAyNSwgc2l6ZT0wLjI1KSArCiAgI2dlb21fZGVuc2l0eV8yZChjb2xvcj0iYmxhY2siLCBhbHBoYT0wLjUsIGJpbnM9NCkgKwogICNmYWNldF9ncmlkKFRQQS5waW5lY29uZS5zdWJsaW5lYWdlLnQxfkNvdW50cnlfY29tYmluYXRpb25zMikgKyAKICBmYWNldF9ncmlkKC5+Q291bnRyeV9jb21iaW5hdGlvbnMyKSArIAogIHRoZW1lX2xpZ2h0KCkgKwogICNzY2FsZV95X2xvZzEwKGJyZWFrcz1jKDAuMDEsMSw1LDEwLDIwLDQwKSkgKyBzY2FsZV94X2xvZzEwKGJyZWFrcz1jKDAuMDEsMSw1LDEwLDIwKSkgKwogICNjb29yZF9jYXJ0ZXNpYW4oeGxpbT1jKDAuMSwyMCksIHlsaW09YygwLjEsMzApKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoMCwyNSw1KSkgKwogIGxhYnMoeT0iUGFpcndpc2UgU05QIGRpc3RhbmNlIiwgeD0iUGFpcndpc2UgdGltZSBkaXN0YW5jZSAoeWVhcnMpIikgKwogIHRoZW1lLnRleHQuc2l6ZSArIHRoZW1lKGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC43NSwibGluZSIpKSArCiAgdGhlbWUoc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPSd3aGl0ZScsbGluZXR5cGU9InNvbGlkIiksIHN0cmlwLnRleHQueD1lbGVtZW50X3RleHQoY29sb3I9ImdyZXkyNSIsIHNpemU9MTApLCBzdHJpcC50ZXh0Lnk9ZWxlbWVudF90ZXh0KGNvbG9yPSJncmV5MjUiLCBzaXplPTEwKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIikgKwogIGdndGl0bGUoIlBhaXJ3aXNlIFNOUHMgKHNhbWUgc3VibGluZWFnZSkgYW5kIFllYXJzIHdpdGhpbiBhbmQgYmV0d2VlbiBCcml0aXNoIENvbHVtYmlhIChDYW5hZGEpIGFuZCBFbmdsYW5kIChVSykiKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkKCgpwLlVLLmNhbmFkYS5wd1NOUHMudnMuVGltZS5oZXguc3VibGluZWFnZS5icmVha2Rvd24gPC0gcC5VSy5jYW5hZGEucHdTTlBzLnZzLlRpbWUuaGV4LnN1YmxpbmVhZ2UuYnJlYWtkb3duICsgc3RhdF9zbW9vdGgobWV0aG9kPSdsbScsIGZ1bGxyYW5nZT1GLHNlPVQsIGNvbG9yPSdibGFjaycsIGxldmVsPTk1KQojcC5VSy5jYW5hZGEucHdTTlBzLnZzLlRpbWUuaGV4LnN1YmxpbmVhZ2UuYnJlYWtkb3duICsgc3RhdF9zbW9vdGgoZnVsbHJhbmdlPUYsc2U9VCwgY29sb3I9J2JsYWNrJywgZm9ybXVsYT1sb2cxMCh4KSB+IGxvZzEwKHgpKQojcC5VSy5jYW5hZGEucHdTTlBzLnZzLlRpbWUuaGV4LnN1YmxpbmVhZ2UuYnJlYWtkb3duCgoKYGBgCkxvb2sgYXQgdGVtcG9yYWwgcmVsYXRpb25zaGlwcyBhIGxpdHRsZSBtb3JlCmBgYHtyfQojIHRpbWUgZGlzdGFuY2VzIGF0IDAgU05QcwptZWFuKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5VSy5DYW5hZGEuZnVsbG1ldGEud2l0aGluLnN1YmxpbmVhZ2VbVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLlVLLkNhbmFkYS5mdWxsbWV0YS53aXRoaW4uc3VibGluZWFnZSREaXN0YW5jZT09MCwieWVhci5kaXN0YW5jZSJdKQptYXgoVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLlVLLkNhbmFkYS5mdWxsbWV0YS53aXRoaW4uc3VibGluZWFnZVtUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhLmZ1bGxtZXRhLndpdGhpbi5zdWJsaW5lYWdlJERpc3RhbmNlPT0wLCJ5ZWFyLmRpc3RhbmNlIl0pCm1pbihUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhLmZ1bGxtZXRhLndpdGhpbi5zdWJsaW5lYWdlW1RQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5VSy5DYW5hZGEuZnVsbG1ldGEud2l0aGluLnN1YmxpbmVhZ2UkRGlzdGFuY2U9PTAsInllYXIuZGlzdGFuY2UiXSkKCiMgbWVhbiBTTlAgZGlzdGFuY2UKbWF4KFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5VSy5DYW5hZGEuZnVsbG1ldGEud2l0aGluLnN1YmxpbmVhZ2UkRGlzdGFuY2UpCiMgbWF4IFNOUCBkaXN0YW5jZSAKbWF4KFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5VSy5DYW5hZGEuZnVsbG1ldGEud2l0aGluLnN1YmxpbmVhZ2UkRGlzdGFuY2UpCgojIHRpbWUgZGlzdGFuY2VzIGF0IDI2IFNOUHMKbWVhbihUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhLmZ1bGxtZXRhLndpdGhpbi5zdWJsaW5lYWdlW1RQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5VSy5DYW5hZGEuZnVsbG1ldGEud2l0aGluLnN1YmxpbmVhZ2UkRGlzdGFuY2U9PTI2LCJ5ZWFyLmRpc3RhbmNlIl0pCm1heChUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhLmZ1bGxtZXRhLndpdGhpbi5zdWJsaW5lYWdlW1RQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5VSy5DYW5hZGEuZnVsbG1ldGEud2l0aGluLnN1YmxpbmVhZ2UkRGlzdGFuY2U9PTI2LCJ5ZWFyLmRpc3RhbmNlIl0pCm1pbihUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhLmZ1bGxtZXRhLndpdGhpbi5zdWJsaW5lYWdlW1RQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5VSy5DYW5hZGEuZnVsbG1ldGEud2l0aGluLnN1YmxpbmVhZ2UkRGlzdGFuY2U9PTI2LCJ5ZWFyLmRpc3RhbmNlIl0pCgoKIyB0aW1lIGRpc3RhbmNlcyBhdCAwIFNOUHMgKENhbmFkYSkKbWVhbihUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhLmZ1bGxtZXRhLndpdGhpbi5zdWJsaW5lYWdlWyhUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhLmZ1bGxtZXRhLndpdGhpbi5zdWJsaW5lYWdlJERpc3RhbmNlPT0wICYgVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLlVLLkNhbmFkYS5mdWxsbWV0YS53aXRoaW4uc3VibGluZWFnZSRDb3VudHJ5X2NvbWJpbmF0aW9ucz09IkNhbmFkYV9fX0NhbmFkYSIpLCJ5ZWFyLmRpc3RhbmNlIl0pCm1lYW4oVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLlVLLkNhbmFkYS5mdWxsbWV0YS53aXRoaW4uc3VibGluZWFnZVsoVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLlVLLkNhbmFkYS5mdWxsbWV0YS53aXRoaW4uc3VibGluZWFnZSREaXN0YW5jZT09MCAmIFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5VSy5DYW5hZGEuZnVsbG1ldGEud2l0aGluLnN1YmxpbmVhZ2UkQ291bnRyeV9jb21iaW5hdGlvbnM9PSJVS19fX1VLIiksInllYXIuZGlzdGFuY2UiXSkKbWVhbihUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhLmZ1bGxtZXRhLndpdGhpbi5zdWJsaW5lYWdlWyhUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhLmZ1bGxtZXRhLndpdGhpbi5zdWJsaW5lYWdlJERpc3RhbmNlPT0wICYgVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLlVLLkNhbmFkYS5mdWxsbWV0YS53aXRoaW4uc3VibGluZWFnZSRDb3VudHJ5X2NvbWJpbmF0aW9ucz09IkNhbmFkYV9fX1VLIiksInllYXIuZGlzdGFuY2UiXSkKCgojIyMjIyMjIyMjIyMjIwojIFNOUCBkaXN0YW5jZXMgYXQgMCB0aW1lCm1lYW4oVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLlVLLkNhbmFkYS5mdWxsbWV0YS53aXRoaW4uc3VibGluZWFnZVtUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhLmZ1bGxtZXRhLndpdGhpbi5zdWJsaW5lYWdlJHllYXIuZGlzdGFuY2U9PTAsIkRpc3RhbmNlIl0pCm1heChUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhLmZ1bGxtZXRhLndpdGhpbi5zdWJsaW5lYWdlW1RQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5VSy5DYW5hZGEuZnVsbG1ldGEud2l0aGluLnN1YmxpbmVhZ2UkeWVhci5kaXN0YW5jZT09MCwiRGlzdGFuY2UiXSkKbWluKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5VSy5DYW5hZGEuZnVsbG1ldGEud2l0aGluLnN1YmxpbmVhZ2VbVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLlVLLkNhbmFkYS5mdWxsbWV0YS53aXRoaW4uc3VibGluZWFnZSR5ZWFyLmRpc3RhbmNlPT0wLCJEaXN0YW5jZSJdKQoKbWF4KFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5VSy5DYW5hZGEuZnVsbG1ldGEud2l0aGluLnN1YmxpbmVhZ2UkeWVhci5kaXN0YW5jZSkKIyBTTlAgZGlzdGFuY2VzIGF0IDE5IHllYXJzIHRpbWUKbWVhbihUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhLmZ1bGxtZXRhLndpdGhpbi5zdWJsaW5lYWdlW1RQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5VSy5DYW5hZGEuZnVsbG1ldGEud2l0aGluLnN1YmxpbmVhZ2UkeWVhci5kaXN0YW5jZT09MTksIkRpc3RhbmNlIl0pCm1heChUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhLmZ1bGxtZXRhLndpdGhpbi5zdWJsaW5lYWdlW1RQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5VSy5DYW5hZGEuZnVsbG1ldGEud2l0aGluLnN1YmxpbmVhZ2UkeWVhci5kaXN0YW5jZT09MTksIkRpc3RhbmNlIl0pCm1pbihUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhLmZ1bGxtZXRhLndpdGhpbi5zdWJsaW5lYWdlW1RQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5VSy5DYW5hZGEuZnVsbG1ldGEud2l0aGluLnN1YmxpbmVhZ2UkeWVhci5kaXN0YW5jZT09MTksIkRpc3RhbmNlIl0pCgoKIyBTTlAgZGlzdGFuY2VzIGF0IDAgdGltZSAoRW5nbGFuZCkKbWVhbihUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhLmZ1bGxtZXRhLndpdGhpbi5zdWJsaW5lYWdlWyhUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhLmZ1bGxtZXRhLndpdGhpbi5zdWJsaW5lYWdlJHllYXIuZGlzdGFuY2U9PTAgJiBUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhLmZ1bGxtZXRhLndpdGhpbi5zdWJsaW5lYWdlJENvdW50cnlfY29tYmluYXRpb25zPT0iVUtfX19VSyIpLCJEaXN0YW5jZSJdKQojIFNOUCBkaXN0YW5jZXMgYXQgMCB0aW1lIChDYW5hZGEpCm1lYW4oVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLlVLLkNhbmFkYS5mdWxsbWV0YS53aXRoaW4uc3VibGluZWFnZVsoVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLlVLLkNhbmFkYS5mdWxsbWV0YS53aXRoaW4uc3VibGluZWFnZSR5ZWFyLmRpc3RhbmNlPT0wICYgVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLlVLLkNhbmFkYS5mdWxsbWV0YS53aXRoaW4uc3VibGluZWFnZSRDb3VudHJ5X2NvbWJpbmF0aW9ucz09IkNhbmFkYV9fX0NhbmFkYSIpLCJEaXN0YW5jZSJdKQojIFNOUCBkaXN0YW5jZXMgYXQgMCB0aW1lIChCb3RoKQptZWFuKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5VSy5DYW5hZGEuZnVsbG1ldGEud2l0aGluLnN1YmxpbmVhZ2VbKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5VSy5DYW5hZGEuZnVsbG1ldGEud2l0aGluLnN1YmxpbmVhZ2UkeWVhci5kaXN0YW5jZT09MCAmIFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5VSy5DYW5hZGEuZnVsbG1ldGEud2l0aGluLnN1YmxpbmVhZ2UkQ291bnRyeV9jb21iaW5hdGlvbnM9PSJDYW5hZGFfX19VSyIpLCJEaXN0YW5jZSJdKQoKCmBgYAoKCgojIyMgTG9vayBhdCBmb3JtYWxseSB0ZXN0aW5nIGZvciBzaWduYWwKCkNhbGN1bGF0ZSBQZWFyc29uJ3MgY29ycmVsYXRpb24gKGZvciByZWFsIGRhdGFzZXQpCmBgYHtyfQojVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLlVLLkNhbmFkYS5mdWxsbWV0YS53aXRoaW4uc3VibGluZWFnZVssYygiRGlzdGFuY2UiLCJ5ZWFyLmRpc3RhbmNlIildCgojVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhLlVLLkNhbmFkYS5mdWxsbWV0YS53aXRoaW4uc3VibGluZWFnZQoKCnRlbXBvcmFsLnJlYWwuY29ycmVsYXRpb24xIDwtIGNvcihUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhLmZ1bGxtZXRhLndpdGhpbi5zdWJsaW5lYWdlJERpc3RhbmNlLFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5VSy5DYW5hZGEuZnVsbG1ldGEud2l0aGluLnN1YmxpbmVhZ2UkeWVhci5kaXN0YW5jZSkKCiN0ZW1wb3JhbC5yZWFsLmNvcnJlbGF0aW9uMSA8LSBjb3IudGVzdChUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhLmZ1bGxtZXRhLndpdGhpbi5zdWJsaW5lYWdlJERpc3RhbmNlLFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5VSy5DYW5hZGEuZnVsbG1ldGEud2l0aGluLnN1YmxpbmVhZ2UkeWVhci5kaXN0YW5jZSkKCiMgTm93IGNvbXBhcmUgdG8gcmFuZG9taXNlZCBib290c3RyYXAgc2FtcGxpbmcgKHdpdGggcmVwbGFjZW1lbnQpCnNldC5zZWVkKDEyMzQ1KQpib290c3RyYXAuY291bnQgPC0gMTAwMAp0ZW1wb3JhbC5ib290c3RyYXAuY29ycmVsYXRpb24xIDwtIE5VTEwKZm9yIChib290c3RyYXAgaW4gMTpib290c3RyYXAuY291bnQpeyAKICBzYW1wbGUxIDwtIGRhdGEuZnJhbWUoRGlzdGFuY2U9c2FtcGxlKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5VSy5DYW5hZGEuZnVsbG1ldGEud2l0aGluLnN1YmxpbmVhZ2UkRGlzdGFuY2UscmVwbGFjZT1UKSwgeWVhci5kaXN0YW5jZT1UUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEuVUsuQ2FuYWRhLmZ1bGxtZXRhLndpdGhpbi5zdWJsaW5lYWdlJHllYXIuZGlzdGFuY2UsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQogIHRlbXBvcmFsLmJvb3RzdHJhcC5jb3JyZWxhdGlvbjEgPC0gYyh0ZW1wb3JhbC5ib290c3RyYXAuY29ycmVsYXRpb24xLCBjb3Ioc2FtcGxlMVssMV0sIHNhbXBsZTFbLDJdKSkKfQp0ZW1wb3JhbC5ib290c3RyYXAuY29ycmVsYXRpb24xIDwtIGRhdGEuZnJhbWUoQ29ycmVsYXRpb249dGVtcG9yYWwuYm9vdHN0cmFwLmNvcnJlbGF0aW9uMSwgdHlwZT0iQm9vdHN0cmFwIixzdHJpbmdzQXNGYWN0b3JzPUYpCnRlbXBvcmFsLmJvb3RzdHJhcC5jb3JyZWxhdGlvbjEgPC0gcmJpbmQoZGF0YS5mcmFtZShDb3JyZWxhdGlvbj10ZW1wb3JhbC5yZWFsLmNvcnJlbGF0aW9uMSwgdHlwZT0iUmVhbCIsIHN0cmluZ3NBc0ZhY3RvcnM9RiksdGVtcG9yYWwuYm9vdHN0cmFwLmNvcnJlbGF0aW9uMSkKCgpucm93KFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YS5VSy5DYW5hZGEuZnVsbG1ldGEud2l0aGluLnN1YmxpbmVhZ2UpCgp0ZW1wb3JhbC5ib290c3RyYXAuY29ycmVsYXRpb24xJHB2YWwgPC0gKDErc3VtKHRlbXBvcmFsLmJvb3RzdHJhcC5jb3JyZWxhdGlvbjFbdGVtcG9yYWwuYm9vdHN0cmFwLmNvcnJlbGF0aW9uMSR0eXBlPT0iQm9vdHN0cmFwIiwiQ29ycmVsYXRpb24iXSA+PSB0ZW1wb3JhbC5ib290c3RyYXAuY29ycmVsYXRpb24xW3RlbXBvcmFsLmJvb3RzdHJhcC5jb3JyZWxhdGlvbjEkdHlwZT09IlJlYWwiLCJDb3JyZWxhdGlvbiJdKSkvKG5yb3codGVtcG9yYWwuYm9vdHN0cmFwLmNvcnJlbGF0aW9uMVt0ZW1wb3JhbC5ib290c3RyYXAuY29ycmVsYXRpb24xJHR5cGU9PSJCb290c3RyYXAiLF0pICsxKQojIEFkanVzdCB0byBtaW5pbXVtIHNlbnNpdGl2aXR5IG9mIG1ldGhvZCAoaW4gY2FzZSBvZiB6ZXJvKQp0ZW1wb3JhbC5ib290c3RyYXAuY29ycmVsYXRpb24xJHB2YWwgPC0gaWZlbHNlKHRlbXBvcmFsLmJvb3RzdHJhcC5jb3JyZWxhdGlvbjEkcHZhbD09MCwgMS9ib290c3RyYXAuY291bnQsdGVtcG9yYWwuYm9vdHN0cmFwLmNvcnJlbGF0aW9uMSRwdmFsKQoKZ2dwbG90KHRlbXBvcmFsLmJvb3RzdHJhcC5jb3JyZWxhdGlvbjEsIGFlcyh0eXBlLCBDb3JyZWxhdGlvbikpICsgCiAgZ2VvbV9ib3hwbG90KCkgKyAKICB0aGVtZV9saWdodCgpICsKICAjc2NhbGVfeV9sb2cxMCgpICsKICBnZW9tX3RleHQoZGF0YT10ZW1wb3JhbC5ib290c3RyYXAuY29ycmVsYXRpb24xW3RlbXBvcmFsLmJvb3RzdHJhcC5jb3JyZWxhdGlvbjEkdHlwZT09IlJlYWwiLF0sIGFlcyh0eXBlLCB5PTAuMDc1LCBsYWJlbD1wYXN0ZTAoIkNvcnJlbGF0aW9uPSIscm91bmQodGVtcG9yYWwuYm9vdHN0cmFwLmNvcnJlbGF0aW9uMSRDb3JyZWxhdGlvblsxXSw1KSkpLCBpbmhlcml0LmFlcyA9IEYpICsKICBsYWJzKHg9IkRhdGFzZXQiLCB5PSJDb3JyZWxhdGlvbiIpICsKICBnZW9tX3RleHQoZGF0YT10ZW1wb3JhbC5ib290c3RyYXAuY29ycmVsYXRpb24xW3RlbXBvcmFsLmJvb3RzdHJhcC5jb3JyZWxhdGlvbjEkdHlwZT09IlJlYWwiLF0sIGFlcyh0eXBlLCB5PTAuMDUsIGxhYmVsPXBhc3RlMCgicDwiLHJvdW5kKHRlbXBvcmFsLmJvb3RzdHJhcC5jb3JyZWxhdGlvbjEkcHZhbFsxXSw1KSkpLCBpbmhlcml0LmFlcyA9IEYpICsgCiAgZ2d0aXRsZShwYXN0ZTAoIkVmZmVjdCBvZiB0ZW1wb3JhbCBkaXN0YW5jZSBvbiBwYWlyd2lzZSBnZW5ldGljIGRpc3RhbmNlIGZvciBCQy9FbmdsYW5kXG5zYW1wbGVzIG9mIHRoZSBzYW1lIHN1YmxpbmVhZ2UiLCIgKCIsYm9vdHN0cmFwLmNvdW50LCIgYm9vdHN0cmFwcykiKSkgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpCmBgYAoKCgpDb21iaW5lIHB3U05QIGRhdGEgd2l0aCByZXN0IG9mIENhbmFkYS9VSyBwbG90cwpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTYsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpwbG90LlVLLkJDLnN0YXRzLnZzLmJ1YmJsZXBsb3QgPC0gcGxvdF9ncmlkKHBsb3QuVUsuQkMuc3RhdHMuY29tYmluZWQgKyB4LnRoZW1lLnN0cmlwICsgZ2d0aXRsZSgiU3lwaGlsaXMgSW5jaWRlbmNlIGFuZCBzdWJsaW5lYWdlIGNvdW50IikgK3RoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSksIHBsb3QuVFBBLnN1YmxpbmVhZ2VfVUsuQ2FuYWRhLnRlbXBvcmFsLmNvdW50cy5idWJibGVwbG90ICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iLHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksc3RyaXAudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKSwgbmNvbD0xLCBhbGlnbj1ULCByZWxfaGVpZ2h0cz1jKDEsMiksIGxhYmVscz1jKCdBJywnQicpLCBsYWJlbF9zaXplPTExKQoKI3Bsb3QuVUsuQkMuc3RhdHMudnMuYnViYmxlcGxvdF92c19wYWlyd2lzZS5TTlBzIDwtIHBsb3RfZ3JpZChwbG90LlVLLkJDLnN0YXRzLnZzLmJ1YmJsZXBsb3QsIHAuVUsuY2FuYWRhLnB3U05Qcy52cy5UaW1lLmhleCwgbmNvbD0yLCByZWxfd2lkdGhzPWMoNSw2KSwgbGFiZWxzPWMoJycsJ0MnKSwgbGFiZWxfc2l6ZT0xMSkKCnBsb3QuVUsuQkMuc3RhdHMudnMuYnViYmxlcGxvdF92c19wYWlyd2lzZS5TTlBzIDwtIHBsb3RfZ3JpZChwbG90LlVLLkJDLnN0YXRzLnZzLmJ1YmJsZXBsb3QsIHAuVUsuY2FuYWRhLnB3U05Qcy5zaW5hLCBuY29sPTIsIHJlbF93aWR0aHM9Yyg3LDUpLCBsYWJlbHM9YygnJywnQycpLCBsYWJlbF9zaXplPTExKQoKCgpwbG90LlVLLkJDLnN0YXRzLnZzLmJ1YmJsZXBsb3RfdnNfcGFpcndpc2UuU05QcwpgYGAKCgpDb21iaW5lIHRvIG1ha2UgYSBCQyB2cyBVSyBvbmx5IHBsb3QKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTExLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKI3Bsb3QuVUsuQkMuc3RhdHMudnMuYnViYmxlcGxvdAojcC5VSy5jYW5hZGEucHdTTlBzLnZzLlRpbWUuaGV4LnN1YmxpbmVhZ2UuYnJlYWtkb3duCgoKI0NhaXJvOjpDYWlybyhmaWxlPXBhc3RlMChGaWd1cmVfb3V0cHV0X2RpcmVjdG9yeSwgIlN1cHBsZW1lbnRhcnlfRmlndXJlMTNfQ2FuYWRhLXZzLVVLX2Rpc3Ryb3NfMDMtMjAyMS5zdmciKSwgd2lkdGggPSA2MDAsIGhlaWdodCA9IDEwNTAsdHlwZT0ic3ZnIix1bml0cyA9ICJwdCIpCnBsb3RfZ3JpZChwbG90LlVLLkJDLnN0YXRzLnZzLmJ1YmJsZXBsb3QsIHAuVUsuY2FuYWRhLnB3U05Qcy5zaW5hLCBwLlVLLmNhbmFkYS5wd1NOUHMudnMuVGltZS5oZXguc3VibGluZWFnZS5icmVha2Rvd24sIG5jb2w9MSwgbGFiZWxzPWMoJycsJ0MnLCdEJyksIGxhYmVsX3NpemU9MTEsIHNjYWxlPTAuOTUsIHJlbF9oZWlnaHRzPWMoNCwyLDMpKQojZGV2Lm9mZigpCmBgYAoKCgoKQ29tYmluZSBDYW5hZGEvVUsgYW5hbHlzaXMgd2l0aCBHbG9iYWwgUGFpcndpc2UgYW5hbHlzaXMKYGBge3IsIGZpZy53aWR0aD0xNCwgZmlnLmhlaWdodD0xMiwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCgpwbG90X2dyaWQocGxvdC5VSy5CQy5zdGF0cy52cy5idWJibGVwbG90X3ZzX3BhaXJ3aXNlLlNOUHMsIG11bHRpY291bnRyeS5wYWlyd2lzZS5zbnBzLmdyaWQsIG5jb2w9MSwgc2NhbGU9MC45NSkKCmBgYAoKCgoKCgpEbyBwYWlyd2lzZSBTTlBzIHdpdGhpbiBzdWJsaW5lYWdlcwpgYGB7cn0KCiNUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEkR2VvX0NvdW50cnkudDEgPC0gZmFjdG9yKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSRHZW9fQ291bnRyeS50MSwgbGV2ZWxzPWNvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MiRHZW9fQ291bnRyeSkKClRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSRUUEEucGluZWNvbmUuc3VibGluZWFnZS50MSA8LSBmYWN0b3IoVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlLnQxLCBsZXZlbHM9c3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2UpCgojc2NhbGVfY29sb3JfbWFudWFsKG5hbWU9IlN1YmxpbmVhZ2UiLHZhbHVlcz1zdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZS5jb2xzLCBicmVha3M9c3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2UpCgpwLnBhaXJ3aXNlLnNucHMud2l0aGluLlN1YmxpbmVhZ2UgPC0gZ2dwbG90KFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YVsoVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhJHNhbWUuVFBBLlBpbmVjb25lLmNsdXN0ZXI9PSJzYW1lIiAmIFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSRzYW1lLnNhbXBsZT09ImRpZmZlcmVudCIpLF0sIGFlcyhUUEEucGluZWNvbmUuc3VibGluZWFnZS50MSwgRGlzdGFuY2UsIGNvbG9yPVRQQS5waW5lY29uZS5zdWJsaW5lYWdlLnQxKSkgKwogIGdlb21fdmlvbGluKHNjYWxlPSd3aWR0aCcpICsKICBnZW9tX3NpbmEoYWxwaGE9MC41LCBzY2FsZT0nd2lkdGgnLCBtZXRob2Q9ImQiKSArIAogIHRoZW1lX2xpZ2h0KCkgKwogIHRoZW1lLnRleHQuc2l6ZSArIAogICN4LnRoZW1lLmF4aXMucm90YXRlICsKICBsYWJzKHg9IlN1YmxpbmVhZ2UiLHk9IlBhaXJ3aXNlIFNOUHMiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWU9IlN1YmxpbmVhZ2UiLHZhbHVlcz1zdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZS5jb2xzLCBicmVha3M9c3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2UpICsKICB0aGVtZShsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNjUsImxpbmUiKSxsZWdlbmQucG9zaXRpb249J25vbmUnKSArIAogIGdndGl0bGUoIlBhaXJ3aXNlIFNOUCBkaXN0cmlidXRpb25zIGJldHdlZW4gc2FtcGxlcyBmcm9tIHNhbWUgc3VibGluZWFnZSIpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKSArIAogIE5VTEwKCgpwLnBhaXJ3aXNlLnNucHMud2l0aGluLlN1YmxpbmVhZ2UKCmBgYAoKSnVzdCBjaGVjayB0aGUgbWF4aW11bSBwYWlyd2lzZSBTTlBzIHdpdGhpbiBzdWJsaW5lYWdlcwoKYGBge3J9Cm1heChUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGFbKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSRzYW1lLlRQQS5QaW5lY29uZS5jbHVzdGVyPT0ic2FtZSIgJiBUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEkc2FtZS5zYW1wbGU9PSJkaWZmZXJlbnQiKSwiRGlzdGFuY2UiXSkKCm1heChUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGFbKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSRzYW1lLlRQQS5QaW5lY29uZS5jbHVzdGVyPT0ic2FtZSIgJiBUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEkc2FtZS5zYW1wbGU9PSJkaWZmZXJlbnQiICYgVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlLnQxPT0xOSksIkRpc3RhbmNlIl0pCgpgYGAKCgoKCiMgbmV0d29ya3Mgb2YgbGluZWFnZSBzaGFyaW5nCgpDcmVhdGUgYSBuZXR3b3JrIG9mIGNvdW50cnkgbGlua3MgKHNpbXBseSBiYXNlZCBvbiBjb29jY3VycmVuY2Ugb2Ygc3VibGluZWFnZXMpIC0gbWFrZSBhIGhlYXRtYXAgYmFzZWQgb24gdGhlIGxpbmtsaXN0CgpgYGB7cn0KCmNvdW50cnkuY29tYmluYXRpb25zIDwtIGRhdGEuZnJhbWUodChjb21ibihkYXRhLmZyYW1lKGNvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MilbY29udGluZW50YWwuY291bnRyeS5jb2xzLmJyZXcyJEdlb19Db3VudHJ5IT0iQmVsZ2l1bSIsIkdlb19Db3VudHJ5Il0sMiwgc2ltcGxpZnk9VCkpLHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQpjb2xuYW1lcyhjb3VudHJ5LmNvbWJpbmF0aW9ucykgPC0gYygidGF4YTEiLCJ0YXhhMiIpCmNvdW50cnkuY29tYmluYXRpb25zIDwtIHJiaW5kKGNvdW50cnkuY29tYmluYXRpb25zLGRhdGEuZnJhbWUodGF4YTE9Y291bnRyeS5jb21iaW5hdGlvbnMkdGF4YTIsIHRheGEyPWNvdW50cnkuY29tYmluYXRpb25zJHRheGExLCBzdHJpbmdzQXNGYWN0b3JzID0gRikpCmNvdW50cnkuY29tYmluYXRpb25zJGNvbWJvIDwtIHBhc3RlMChjb3VudHJ5LmNvbWJpbmF0aW9ucyR0YXhhMSwiX19fIixjb3VudHJ5LmNvbWJpbmF0aW9ucyR0YXhhMikKCgpzdWJsaW5lYWdlLmNvdW50cnkuc3VtbWFyeS5zaW1wbGUgPC0gZGF0YS5mcmFtZShUUEEubWV0YTEuMi5waW5lY29uZVtUUEEubWV0YTEuMi5waW5lY29uZSRUUEEucGluZWNvbmUuc3VibGluZWFnZSE9IlNpbmdsZXRvbiIsXSAlPiUgZHBseXI6Omdyb3VwX2J5KFRQQS5waW5lY29uZS5zdWJsaW5lYWdlLEdlb19Db3VudHJ5KSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZSh0b3RhbC5zYW1wbGVzPW4oKSksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQpzdWJsaW5lYWdlLmNvdW50cnkuc3VtbWFyeS5zaW1wbGUgPC0gcGx5cjo6am9pbihzdWJsaW5lYWdlLmNvdW50cnkuc3VtbWFyeS5zaW1wbGUsdW5pcXVlKFRQQS5tZXRhMS4yLnBpbmVjb25lWyxjKCJUUEEucGluZWNvbmUuc3VibGluZWFnZSIsIlRQQS5waW5lY29uZS5tYWpvciIpXSksIGJ5PSJUUEEucGluZWNvbmUuc3VibGluZWFnZSIpCgoKI3N1YmxpbmVhZ2Uuc2hhcmluZy5saW5rcy5hbGwgPC0gc3VibGluZWFnZS5zaGFyaW5nLmxpc3QKc3VibGluZWFnZS5zaGFyaW5nLmxpbmtzLmFsbCA8LSBkYXRhLmZyYW1lKHN1YmxpbmVhZ2UuY291bnRyeS5zdW1tYXJ5LnNpbXBsZSAlPiUgZHBseXI6Omdyb3VwX2J5KFRQQS5waW5lY29uZS5zdWJsaW5lYWdlKSAlPiUgZHBseXI6OnN1bW1hcmlzZShub19saW5rcyA9IGxlbmd0aChUUEEucGluZWNvbmUuc3VibGluZWFnZSkpLHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQpzdWJsaW5lYWdlLnNoYXJpbmcubGlua3MgPC0gc3Vic2V0KHN1YmxpbmVhZ2Uuc2hhcmluZy5saW5rcy5hbGwsIG5vX2xpbmtzPjEpCgoKIyBNYWtlIGxpc3Qgb2YgaW50ZXJhY3Rpb24gY29tYm9zIChpLmUuIG5ldHdvcmsgZWRnZXMpCmxpbmtsaXN0LmFsbCA8LSBOVUxMCmZvciAoY3VycmVudCBpbiBzdWJsaW5lYWdlLnNoYXJpbmcubGlua3MuYWxsJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlKXsKICBjdXJyZW50LnN1YmxpbmVhZ2UgPC0gc3Vic2V0KHN1YmxpbmVhZ2UuY291bnRyeS5zdW1tYXJ5LnNpbXBsZSxUUEEucGluZWNvbmUuc3VibGluZWFnZT09Y3VycmVudCkKICBpZiAobnJvdyhjdXJyZW50LnN1YmxpbmVhZ2UpPjEpewogICAgY3VycmVudC5zdWJsaW5lYWdlMSA8LSBkYXRhLmZyYW1lKHRheGExPXQoY29tYm4oY3VycmVudC5zdWJsaW5lYWdlJEdlb19Db3VudHJ5LCAyLCBGVU49TlVMTCwgc2ltcGxpZnk9VCkpWywxXSx0YXhhMj10KGNvbWJuKGN1cnJlbnQuc3VibGluZWFnZSRHZW9fQ291bnRyeSwgMiwgRlVOPU5VTEwsIHNpbXBsaWZ5PVQpKVssMl0sc3RyaW5nc0FzRmFjdG9ycz1UKQogIGN1cnJlbnQuc3VibGluZWFnZTEkc3VibGluZWFnZSA8LSBjdXJyZW50CiAgbGlua2xpc3QuYWxsIDwtIHJiaW5kKGxpbmtsaXN0LmFsbCwgY3VycmVudC5zdWJsaW5lYWdlMSkKICB9Cn0KCmxpbmtsaXN0LmFsbCA8LSBkYXRhLmZyYW1lKGxpbmtsaXN0LmFsbCwgc3RyaW5nc0FzRmFjdG9ycz1GKQpsaW5rbGlzdC5hbGwkY29tYm8gPC0gcGFzdGUwKGxpbmtsaXN0LmFsbCR0YXhhMSwiX19fIixsaW5rbGlzdC5hbGwkdGF4YTIpCmxpbmtsaXN0LmFsbCRjb21ibzIgPC0gcGFzdGUwKGxpbmtsaXN0LmFsbCR0YXhhMiwiX19fIixsaW5rbGlzdC5hbGwkdGF4YTEpCgoKbGlua2xpc3QuYWxsIDwtIHJiaW5kKGRhdGEuZnJhbWUodGF4YTE9bGlua2xpc3QuYWxsJHRheGExLHRheGEyPWxpbmtsaXN0LmFsbCR0YXhhMiwgc3VibGluZWFnZT1saW5rbGlzdC5hbGwkc3VibGluZWFnZSxjb21ibz1saW5rbGlzdC5hbGwkY29tYm8sIHN0cmluZ3NBc0ZhY3RvcnMgPUYpLCBkYXRhLmZyYW1lKHRheGExPWxpbmtsaXN0LmFsbCR0YXhhMix0YXhhMj1saW5rbGlzdC5hbGwkdGF4YTEsIHN1YmxpbmVhZ2U9bGlua2xpc3QuYWxsJHN1YmxpbmVhZ2UsY29tYm89bGlua2xpc3QuYWxsJGNvbWJvMiwgc3RyaW5nc0FzRmFjdG9ycyA9RikpCgoKbGlua2xpc3QuYWxsLmZyZXF1ZW5jeSA8LSBsaW5rbGlzdC5hbGwgJT4lIGRwbHlyOjpncm91cF9ieShjb21ibywgLmRyb3A9RikgJT4lCiAgZHBseXI6OnN1bW1hcmlzZShTdWJsaW5lYWdlLkNvdW50PW4oKSkKbGlua2xpc3QuYWxsIDwtIHBseXI6OmpvaW4obGlua2xpc3QuYWxsLGxpbmtsaXN0LmFsbC5mcmVxdWVuY3ksIGJ5PSJjb21ibyIsIHR5cGU9J2xlZnQnKQoKbGlua2xpc3QuYWxsMiA8LSBwbHlyOjpqb2luKGNvdW50cnkuY29tYmluYXRpb25zWyxjKCJ0YXhhMSIsInRheGEyIiwiY29tYm8iKV0sbGlua2xpc3QuYWxsWyxjKCJ0YXhhMSIsInRheGEyIiwiY29tYm8iLCJTdWJsaW5lYWdlLkNvdW50IildLCB0eXBlPSJsZWZ0IikKbGlua2xpc3QuYWxsMiA8LSBsaW5rbGlzdC5hbGwyW3JldihvcmRlcihsaW5rbGlzdC5hbGwyJGNvbWJvLCBsaW5rbGlzdC5hbGwyJFN1YmxpbmVhZ2UuQ291bnQpKSxdCmxpbmtsaXN0LmFsbDIgPC1saW5rbGlzdC5hbGwyWyFkdXBsaWNhdGVkKGxpbmtsaXN0LmFsbDIpLF0KbGlua2xpc3QuYWxsIDwtIGxpbmtsaXN0LmFsbDIKCgpsaW5rbGlzdC5hbGxbaXMubmEobGlua2xpc3QuYWxsJFN1YmxpbmVhZ2UuQ291bnQpLCJTdWJsaW5lYWdlLkNvdW50Il0gPC0gMAoKCmxpbmtsaXN0LmFsbCR0YXhhMSA8LSBmYWN0b3IobGlua2xpc3QuYWxsJHRheGExLCBsZXZlbHM9Y29udGluZW50YWwuY291bnRyeS5jb2xzLmJyZXcyJEdlb19Db3VudHJ5KQpsaW5rbGlzdC5hbGwkdGF4YTIgPC0gZmFjdG9yKGxpbmtsaXN0LmFsbCR0YXhhMiwgbGV2ZWxzPWNvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MiRHZW9fQ291bnRyeSkKCnAuY291bnRyeS5zdWJsaW5lYWdlLmxpbmdzLmhlYXRtYXAgPC0gZ2dwbG90KGxpbmtsaXN0LmFsbCwgYWVzKHRheGExLCB0YXhhMiwgZmlsbD1TdWJsaW5lYWdlLkNvdW50KSkgKwogIGdlb21fdGlsZShjb2xvcj0id2hpdGUiKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9IiNmZmZmY2MiLGhpZ2g9IiMyYzdmYjgiLCBuYW1lPSJTaGFyZWRcbnN1YmxpbmVhZ2VzIikgKyAKICAjdGhlbWVfY2xhc3NpYygpICsgCiAgdGhlbWVfbGlnaHQoKSArIAogIHRoZW1lLnRleHQuc2l6ZSArIAogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT05MCxoanVzdD0xLHZqdXN0PTAuNSksIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gU3VibGluZWFnZS5Db3VudCksIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDIuNSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG91cj1kYXRhLmZyYW1lKGNvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MilbY29udGluZW50YWwuY291bnRyeS5jb2xzLmJyZXcyJEdlb19Db3VudHJ5IT0iQmVsZ2l1bSIsImNvdW50cnkuY29sIl0pLCBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChjb2xvdXI9ZGF0YS5mcmFtZShjb250aW5lbnRhbC5jb3VudHJ5LmNvbHMuYnJldzIpW2NvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MiRHZW9fQ291bnRyeSE9IkJlbGdpdW0iLCJjb3VudHJ5LmNvbCJdKSkgKwogIHRoZW1lKGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC43NSwibGluZSIpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIGdndGl0bGUoIk51bWJlciBvZiBzdWJsaW5lYWdlcyBzaGFyZWQgYmV0d2VlbiBjb3VudHJpZXMiKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkKICAKcC5jb3VudHJ5LnN1YmxpbmVhZ2UubGluZ3MuaGVhdG1hcAoKYGBgCgpQbG90IGxpbmVhZ2Ugc2hhcmluZyBuZXR3b3JrIHdpdGggY2xhc3NpZmllZCBsaW5lYWdlIGNvdW50cwpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9NywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCnAuc2hhcmVkLnN1YmxpbmVhZ2UubGVnZW5kIDwtIHBsb3RfZ3JpZChnZXRfbGVnZW5kKHBsb3QuY2xhc3NpZmllZC5zdWJsaW5lYWdlcy5wZXIuY291bnRyeSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ncmlnaHQnKSksIGdldF9sZWdlbmQocC5jb3VudHJ5LnN1YmxpbmVhZ2UubGluZ3MuaGVhdG1hcCArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ncmlnaHQnKSksIG5jb2w9MSwgcmVsX2hlaWdodHM9YygyLDMpKQoKcC5zaGFyZWQuc3VibGluZWFnZS5wbG90Z3JpZCA8LSAgcGxvdF9ncmlkKHBsb3QuY2xhc3NpZmllZC5zdWJsaW5lYWdlcy5wZXIuY291bnRyeSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsgZ2d0aXRsZSgiTnVtYmVyIG9mIHN1YmxpbmVhZ2VzIGluIGVhY2ggY291bnRyeSIpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSkgKyB4LnRoZW1lLnN0cmlwLCBwLmNvdW50cnkuc3VibGluZWFnZS5saW5ncy5oZWF0bWFwICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiksIGFsaWduPVQsIG5jb2w9MSwgcmVsX2hlaWdodHM9YygyLDMpLGxhYmVscz1jKCdBJywnQicpLCBsYWJlbF9zaXplPTExKQoKcGxvdF9ncmlkKHAuc2hhcmVkLnN1YmxpbmVhZ2UucGxvdGdyaWQscC5zaGFyZWQuc3VibGluZWFnZS5sZWdlbmQsIG5jb2w9MiwgcmVsX3dpZHRocz1jKDQsMSkpCgoKYGBgCgoKClRyeSBwbG90IGEgZGlmZmVyZW50IHdheSAoMDItMjAyMSkgdG8gZm9jdXMgb24gZ2xvYmFsIGFuYWx5c2lzIGFsb25lCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgojIFNvcnQgbGFiZWxzCnBsb3QucGFpcndpc2UuU05Qcy5jb21iaS41IDwtIHBsb3RfZ3JpZChwbG90LmNsYXNzaWZpZWQuc3VibGluZWFnZXMucGVyLmNvdW50cnkgKyB4LnRoZW1lLnN0cmlwICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKyBsYWJzKHk9IlN1YmxpbmVhZ2UgQ291bnQiKSwgcC5ocS5jb3VudHJ5LmJhcnBsb3QgKyB4LnRoZW1lLnN0cmlwICsgZ2d0aXRsZSgnU2FtcGxlIGNvdW50IGJ5IGNvdW50cnknKSArIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTApKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwLmNvdW50cnkubWluc25wLmhlYXRtYXAgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArIGdndGl0bGUoJ01pbmltdW0gcGFpcndpc2UgU05QIGRpc3RhbmNlIGJldHdlZW4gY291bnRyaWVzJykgKyB0aGVtZShwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTEwKSksIG5jb2w9MSwgcmVsX2hlaWdodHM9YygxLDEsNCksIGFsaWduPSJ2IiwgYXhpcz0ibHIiLCBsYWJlbHM9YygnQScsJ0InLCdEJyksIGxhYmVsX3NpemU9MTEpCgpwbG90LnBhaXJ3aXNlLlNOUHMuY29tYmkuNSA8LSBwbG90X2dyaWQocGxvdC5wYWlyd2lzZS5TTlBzLmNvbWJpLjUsIHAucGFpcndpc2Uuc25wcy53aXRoaW5Db3VudHJ5LndpdGhpbi5hbGwuTGluZWFnZSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0nbm9uZScpLCBuY29sPTIsIGxhYmVscz1jKCcnLCdDJyksIGxhYmVsX3NpemU9MTEsIHNjYWxlPTAuOTUpCgoKCiMgU29ydCBsYWJlbHMKcGxvdC5wYWlyd2lzZS5TTlBzLmNvbWJpLjYgPC0gcGxvdF9ncmlkKHBsb3QuY2xhc3NpZmllZC5zdWJsaW5lYWdlcy5wZXIuY291bnRyeSArIHgudGhlbWUuc3RyaXAgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArIGxhYnMoeT0iU3VibGluZWFnZSBDb3VudCIpLCBwLmhxLmNvdW50cnkuYmFycGxvdCArIGdndGl0bGUoJ1NhbXBsZSBjb3VudCBieSBjb3VudHJ5JykgKyB0aGVtZShwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTEwKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcC5jb3VudHJ5Lm1pbnNucC5oZWF0bWFwICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKyBnZ3RpdGxlKCdNaW5pbXVtIHBhaXJ3aXNlIFNOUCBkaXN0YW5jZSBiZXR3ZWVuIGNvdW50cmllcycpICsgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xMCkpLCBuY29sPTEsIHJlbF9oZWlnaHRzPWMoMSwyLDQpLCBhbGlnbj0idiIsIGF4aXM9ImxyIiwgbGFiZWxzPWMoJ0EnLCdCJywnRCcpLCBsYWJlbF9zaXplPTExKQoKcGxvdC5wYWlyd2lzZS5TTlBzLmNvbWJpLjYgPC0gcGxvdF9ncmlkKHBsb3QucGFpcndpc2UuU05Qcy5jb21iaS42LCBwLnBhaXJ3aXNlLnNucHMud2l0aGluQ291bnRyeS53aXRoaW4uYWxsLkxpbmVhZ2UgKyB0aGVtZShsZWdlbmQucG9zaXRpb249J25vbmUnKSwgbmNvbD0yLCBsYWJlbHM9YygnJywnQycpLCBsYWJlbF9zaXplPTExLCBzY2FsZT0wLjk1KQoKCgoKcHdTTlBzLmxlZ2VuZCA8LSBnZXRfbGVnZW5kKHAucGFpcndpc2Uuc25wcy53aXRoaW5Db3VudHJ5LndpdGhpbi5hbGwuTGluZWFnZSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ndG9wJykpCnB3U05Qcy5oZWF0bWFwLmxlZ2VuZCA8LSBnZXRfbGVnZW5kKHAuY291bnRyeS5taW5zbnAuaGVhdG1hcCArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ndG9wJykpCnN1YmxpbmVhZ2VzLmxlZ2VuZCA8LSBnZXRfbGVnZW5kKHBsb3QuY2xhc3NpZmllZC5zdWJsaW5lYWdlcy5wZXIuY291bnRyeSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ndG9wJykgKyBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQobnJvdz0zKSkpCmNvdW50cmllcy5iYXIubGVnZW5kIDwtIGdldF9sZWdlbmQocC5ocS5jb3VudHJ5LmJhcnBsb3QgKyB0aGVtZShsZWdlbmQucG9zaXRpb249J3RvcCcpICsgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKG5yb3c9NikpKQoKRmlndXJlMy5jb21iaS5sZWdlbmQgPC0gcGxvdF9ncmlkKHN1YmxpbmVhZ2VzLmxlZ2VuZCxwd1NOUHMuaGVhdG1hcC5sZWdlbmQsY291bnRyaWVzLmJhci5sZWdlbmQsIG5yb3c9MSwgcmVsX3dpZHRocz1jKDIsMSwzKSkKCnB3U05Qcy5sZWdlbmQudmVydCA8LSBnZXRfbGVnZW5kKHAucGFpcndpc2Uuc25wcy53aXRoaW5Db3VudHJ5LndpdGhpbi5hbGwuTGluZWFnZSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0nbGVmdCcpKQpwd1NOUHMuaGVhdG1hcC5sZWdlbmQudmVydCA8LSBnZXRfbGVnZW5kKHAuY291bnRyeS5taW5zbnAuaGVhdG1hcCArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0nbGVmdCcpKQpzdWJsaW5lYWdlcy5sZWdlbmQudmVydCA8LSBnZXRfbGVnZW5kKHBsb3QuY2xhc3NpZmllZC5zdWJsaW5lYWdlcy5wZXIuY291bnRyeSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0nbGVmdCcpICsgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKG5jb2w9MSkpKQpjb3VudHJpZXMuYmFyLmxlZ2VuZC52ZXJ0IDwtIGdldF9sZWdlbmQocC5ocS5jb3VudHJ5LmJhcnBsb3QgKyB0aGVtZShsZWdlbmQucG9zaXRpb249J2xlZnQnKSArIGd1aWRlcyhmaWxsPWd1aWRlX2xlZ2VuZChuY29sPTEpKSkKCkZpZ3VyZTMuY29tYmkubGVnZW5kLnZlcnQgPC0gcGxvdF9ncmlkKHN1YmxpbmVhZ2VzLmxlZ2VuZC52ZXJ0LHB3U05Qcy5oZWF0bWFwLmxlZ2VuZC52ZXJ0LGNvdW50cmllcy5iYXIubGVnZW5kLnZlcnQsIG5jb2w9MSwgcmVsX2hlaWdodHM9YygyLDEsMykpCgoKCiMjIyMKIyBWZXJzaW9uIDcgb2YgdGhpcyBjb21wbGV4IGFuZCBtdWNoIGNvbW1lbnRlZCBvbiBwbG90IDstKSAKCkZpZ3VyZTMuY29tYmkubGVnZW5kLm1peGl0MSA8LSBwbG90X2dyaWQoc3VibGluZWFnZXMubGVnZW5kLGNvdW50cmllcy5iYXIubGVnZW5kLCBucm93PTIsIHJlbF9oZWlnaHRzPWMoMiwzKSkKCiMgU29ydCBGaWd1cmUgYW5kIGxhYmVscwpwbG90LnBhaXJ3aXNlLlNOUHMuY29tYmkuNyA8LSBwbG90X2dyaWQocGxvdC5jbGFzc2lmaWVkLnN1YmxpbmVhZ2VzLnBlci5jb3VudHJ5ICsgeC50aGVtZS5zdHJpcCArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsgbGFicyh5PSJTdWJsaW5lYWdlIENvdW50IiksIHAuaHEuY291bnRyeS5iYXJwbG90ICsgeC50aGVtZS5zdHJpcCArIGdndGl0bGUoJ1NhbXBsZSBjb3VudCBieSBjb3VudHJ5JykgKyB0aGVtZShwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTEwKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcC5jb3VudHJ5Lm1pbnNucC5oZWF0bWFwICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKyBnZ3RpdGxlKCdNaW5pbXVtIHBhaXJ3aXNlIFNOUCBkaXN0YW5jZSBiZXR3ZWVuIGNvdW50cmllcycpICsgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xMCkpLCBuY29sPTEsIHJlbF9oZWlnaHRzPWMoMSwxLDQpLCBhbGlnbj0idiIsIGF4aXM9ImxyIiwgbGFiZWxzPWMoJ0EnLCdCJywnRCcpLCBsYWJlbF9zaXplPTExKQpwbG90LnBhaXJ3aXNlLlNOUHMuY29tYmkuNy5hIDwtIHBsb3RfZ3JpZChwbG90LnBhaXJ3aXNlLlNOUHMuY29tYmkuNywgcHdTTlBzLmhlYXRtYXAubGVnZW5kLCByZWxfaGVpZ2h0cz1jKDExLDEpLG5jb2w9MSkKCnBsb3QucGFpcndpc2UuU05Qcy5jb21iaS43LmIgPC0gcGxvdF9ncmlkKEZpZ3VyZTMuY29tYmkubGVnZW5kLm1peGl0MSxwLnBhaXJ3aXNlLnNucHMud2l0aGluQ291bnRyeS53aXRoaW4uYWxsLkxpbmVhZ2UgKyB0aGVtZShsZWdlbmQucG9zaXRpb249J25vbmUnKSxuY29sPTEsIHJlbF9oZWlnaHRzPWMoMSw0KSwgbGFiZWxzPWMoJycsJ0MnKSwgbGFiZWxfc2l6ZT0xMSwgc2NhbGU9MC45NSkgIAoKcGxvdC5wYWlyd2lzZS5TTlBzLmNvbWJpLjcuYyA8LSBwbG90X2dyaWQocGxvdC5wYWlyd2lzZS5TTlBzLmNvbWJpLjcuYSwgcGxvdC5wYWlyd2lzZS5TTlBzLmNvbWJpLjcuYiwgbmNvbD0yKQoKCgoKCgojQ2Fpcm86OkNhaXJvKGZpbGU9cGFzdGUwKEZpZ3VyZV9vdXRwdXRfZGlyZWN0b3J5LCAiRmlndXJlNF9TdWJsaW4rUGFpcndpc2VTTlBzX19HbG9iYWwtZGlzdHJvXzAyLTIwMjEuc3ZnIiksIHdpZHRoID0gODAwLCBoZWlnaHQgPSA4MDAsdHlwZT0ic3ZnIix1bml0cyA9ICJwdCIpCnBsb3QucGFpcndpc2UuU05Qcy5jb21iaS43LmMKI2Rldi5vZmYoKQpgYGAKCgoKCgpcCiMgbmVlZCB0byBkbyBhIHRyZWUgdGhhdCBvbmx5IGhpZ2hsaWdodHMgc2luZ2xldG9uIG9yIHByaXZhdGUgc3VibGluZWFnZXNcCgpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKcHJpdmF0ZS5zaW5nbGV0b24ubGluZWFnZXMgPC0gZGF0YS5mcmFtZShQcml2YXRlLmNvdW50cnkuY291bnRzW1ByaXZhdGUuY291bnRyeS5jb3VudHMkcHJpdmF0ZS5kaXN0cm89PSJwcml2YXRlIixjKCJUUEEucGluZWNvbmUuc3VibGluZWFnZSIsInByaXZhdGUuZGlzdHJvIildKQoKcHJpdmF0ZS5zaW5nbGV0b24ubGluZWFnZXMgPC0gcmJpbmQocHJpdmF0ZS5zaW5nbGV0b24ubGluZWFnZXMsZGF0YS5mcmFtZShUUEEucGluZWNvbmUuc3VibGluZWFnZT0iU2luZ2xldG9uIixwcml2YXRlLmRpc3Rybz0iU2luZ2xldG9uIixzdHJpbmdzQXNGYWN0b3JzID0gRikpCnByaXZhdGUuc2luZ2xldG9uLmxpbmVhZ2VzJHByaXZhdGUuc3VibGluZWFnZXMgPC0gcHJpdmF0ZS5zaW5nbGV0b24ubGluZWFnZXMkVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UKcHJpdmF0ZS5zaW5nbGV0b24ubGluZWFnZXMgPC0gcHJpdmF0ZS5zaW5nbGV0b24ubGluZWFnZXNbLGMoIlRQQS5waW5lY29uZS5zdWJsaW5lYWdlIiwicHJpdmF0ZS5zdWJsaW5lYWdlcyIpXQoKcHJpdmF0ZS5zaW5nbGV0b24uc2FtcGxlcyA8LSAgcGx5cjo6am9pbihUUEEubWV0YTEuMi5waW5lY29uZVssYygiU2FtcGxlX05hbWUiLCJUUEEucGluZWNvbmUuc3VibGluZWFnZSIpXSxwcml2YXRlLnNpbmdsZXRvbi5saW5lYWdlcywgdHlwZT0ibGVmdCIsIGJ5PSJUUEEucGluZWNvbmUuc3VibGluZWFnZSIpCgpwcml2YXRlLnNpbmdsZXRvbi5zYW1wbGVzIDwtIGRhdGEuZnJhbWUocm93Lm5hbWVzPXByaXZhdGUuc2luZ2xldG9uLnNhbXBsZXMkU2FtcGxlX05hbWUsICJQcml2YXRlIG9yIFNpbmdsZXRvblxuU3VibGluZWFnZSI9cHJpdmF0ZS5zaW5nbGV0b24uc2FtcGxlcyRwcml2YXRlLnN1YmxpbmVhZ2VzKQoKCiMgYWRkIHByaXZhdGUgbGluZWFnZSBzdHJpcCB0byB0cmVlIApwLlRQQS5NTHRyZWUuc3VibGluZWFnZXMucHJpdmF0ZWxpbmVhZ2UgPC0gZ2hlYXRtYXAoVFBBLk1MdHJlZS5nZ3RyZWUudGlwcG9pbnQgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSwKICAgICAgICAgICAgICAgcHJpdmF0ZS5zaW5nbGV0b24uc2FtcGxlcywgY29sb3I9J2dyZXk3MCcsd2lkdGg9MC4wNzUsb2Zmc2V0PTAuMDAwMDA3MjUsIGNvbG5hbWVzX2FuZ2xlPS00NSxjb2xuYW1lc19vZmZzZXRfeT0wLCBoanVzdD0wLGZvbnQuc2l6ZT0yKSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWU9IlByaXZhdGUgJiBTaW5nbGV0b25cblN1YmxpbmVhZ2VzIix2YWx1ZXM9c3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2UuY29scywgYnJlYWtzPXN1YmxpbmVhZ2VzLmNvbHMuYnJldyRzdWJsaW5lYWdlKSArCiAgdGhlbWUudGV4dC5zaXplICsgdGhlbWUobGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjY1LCJsaW5lIiksbGVnZW5kLnBvc2l0aW9uPSdyaWdodCcpCnAuVFBBLk1MdHJlZS5zdWJsaW5lYWdlcy5wcml2YXRlbGluZWFnZSA8LSBwLlRQQS5NTHRyZWUuc3VibGluZWFnZXMucHJpdmF0ZWxpbmVhZ2UgKyBuZXdfc2NhbGVfZmlsbCgpCgoKcC5UUEEuTUx0cmVlLnN1YmxpbmVhZ2VzLnByaXZhdGVsaW5lYWdlIDwtZ2hlYXRtYXAocC5UUEEuTUx0cmVlLnN1YmxpbmVhZ2VzLnByaXZhdGVsaW5lYWdlLFRQQS5yYXdzZXEuY291bnRyaWVzLnAsIGNvbG9yPSdncmV5NzAnLHdpZHRoPTAuMDc1LG9mZnNldD0wLjAwMDAxNzI1LCBjb2xuYW1lc19hbmdsZT0tNDUsY29sbmFtZXNfb2Zmc2V0X3k9MCwgaGp1c3Q9MCxmb250LnNpemU9MikgKyAKICBzY2FsZV9maWxsX21hbnVhbChuYW1lPSJDb3VudHJ5Iix2YWx1ZXM9Y29udGluZW50YWwuY291bnRyeS5jb2xzLmJyZXcyJGNvdW50cnkuY29sLCBicmVha3M9Y29udGluZW50YWwuY291bnRyeS5jb2xzLmJyZXcyJEdlb19Db3VudHJ5KSArCiAgdGhlbWUudGV4dC5zaXplICsgdGhlbWUobGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjY1LCJsaW5lIiksbGVnZW5kLnBvc2l0aW9uPSdyaWdodCcpICsKICBOVUxMCgoKCiNDYWlybzo6Q2Fpcm8oZmlsZT1wYXN0ZTAoRmlndXJlX291dHB1dF9kaXJlY3RvcnksICJTdXBwbGVtZW50YXJ5X0ZpZ3VyZTExX19NTHRyZWVfcHJpdmF0ZStzaW5nbGV0b25fMDItMjAyMS5zdmciKSwgd2lkdGggPSA4MDAsIGhlaWdodCA9IDgwMCx0eXBlPSJzdmciLHVuaXRzID0gInB0IikKcC5UUEEuTUx0cmVlLnN1YmxpbmVhZ2VzLnByaXZhdGVsaW5lYWdlCiNkZXYub2ZmKCkKCgpgYGAKCgoKCk5lZWQgdG8gbWFrZSBhIHN1YnRyZWUgaGlnaGxpZ2h0aW5nIHRoZSBSZWZlcmVuY2Ugc3RyYWlucyBmcm9tIE5pY2hvbHMgbGluZWFnZQpgYGB7cn0KI05pY2hvbHMuY29sbCArIGdlb21fdGV4dDIoYWVzKHN1YnNldD0haXNUaXAsIGxhYmVsPW5vZGUpLCBoanVzdD0tLjMsIHNpemU9Mi41KSAKI2dndHJlZShOaWNob2xzLnJlZi5zdWJ0cmVlLm5vZGVpZC50cmVlKSArIGdlb21fdGV4dDIoYWVzKHN1YnNldD0haXNUaXAsIGxhYmVsPW5vZGUpLCBoanVzdD0tLjMpIAoKI05pY2hvbHMucmVmZXJlbmNlLmNsYWRlLlllYXIuZGF0YSA8LSBkYXRhLmZyYW1lKHJvdy5uYW1lcz1UUEEubWV0YTEuMi5waW5lY29uZS5oYXZlZGF0ZXMkU2FtcGxlX05hbWUsIFRQQS5tZXRhMS4yLnBpbmVjb25lLmhhdmVkYXRlcyRTYW1wbGVfWWVhcixzdHJpbmdzQXNGYWN0b3JzPUYpCgoKTmljaG9scy5yZWYuc3VidHJlZS5ub2RlaWQgPC0gOTc2CiNOaWNob2xzLnJlZi5zdWJ0cmVlLm5vZGVpZCA8LSA5NzkKCk5pY2hvbHMucmVmLnN1YnRyZWUubm9kZWlkLnRyZWUgPC0gdHJlZV9zdWJzZXQoVFBBLk1MdHJlZSwgbm9kZT1OaWNob2xzLnJlZi5zdWJ0cmVlLm5vZGVpZCxsZXZlbHNfYmFjaz0wKQojZ2d0cmVlKE5pY2hvbHMucmVmLnN1YnRyZWUubm9kZWlkLnRyZWUpICsgZ2VvbV90aXBsYWIoc2l6ZT0yLjUpIAoKCgpwLk5pY2hvbHMucmVmLnN1YnRyZWUubm9kZWlkLnRyZWUgPC0gZ2d0cmVlKE5pY2hvbHMucmVmLnN1YnRyZWUubm9kZWlkLnRyZWUpICU8KyUgZGF0YS5mcmFtZShTYW1wbGVfTmFtZT1UUEEubWV0YTEuMi5waW5lY29uZSRTYW1wbGVfTmFtZSwgU3VibGluZWFnZT1UUEEubWV0YTEuMi5waW5lY29uZSRUUEEucGluZWNvbmUuc3VibGluZWFnZSkgKyAKICBnZW9tX3RpcHBvaW50KGFlcyhjb2xvcj1TdWJsaW5lYWdlKSwgc2l6ZT0yLjUsIGFscGhhPTAuMjUsc2hvdy5sZWdlbmQ9RikgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZT0iU3VibGluZWFnZSIsdmFsdWVzPXN1YmxpbmVhZ2VzLmNvbHMuYnJldyRzdWJsaW5lYWdlLmNvbHMsIGJyZWFrcz1zdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZSkgKwogICMgYWRkIGJvb3RzdHJhcCBzdXBwb3J0CiAgZ2VvbV9wb2ludDIoYWVzKHN1YnNldD0oIWlzVGlwICYgYXMubnVtZXJpYyhsYWJlbCk+OTUpKSxzaXplPTIsIHNoYXBlPTE4KSArCiAgZ2VvbV90aXBsYWIoc2l6ZT0yLjUsYWxpZ249RikgKyAKICBnZW9tX3RyZWVzY2FsZShmb250c2l6ZSA9IDIuNSwgeD0wLjAwMDAxLCB5PTEyKSArCiAgI3hsaW0oMCwgMC4wMDAwNykgKwogIE5VTEwKCnAuTmljaG9scy5yZWYuc3VidHJlZS5ub2RlaWQudHJlZS5obSA8LSBnaGVhdG1hcChwLk5pY2hvbHMucmVmLnN1YnRyZWUubm9kZWlkLnRyZWUsCiAgICAgICAgICAgICAgIGRhdGEuZnJhbWUocm93Lm5hbWVzPVRQQS5tZXRhMS4yLnBpbmVjb25lJFNhbXBsZV9OYW1lLCBTdWJsaW5lYWdlPVRQQS5tZXRhMS4yLnBpbmVjb25lJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlKSwgY29sb3I9TlVMTCx3aWR0aD0wLjA2NSxvZmZzZXQ9MC4wMDAwMDk1LCBjb2xuYW1lc19hbmdsZT0wLGNvbG5hbWVzX29mZnNldF95PS0wLjAxLCBmb250LnNpemU9MikgKyAKICBzY2FsZV9maWxsX21hbnVhbChuYW1lPSJTdWJsaW5lYWdlIix2YWx1ZXM9c3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2UuY29scywgYnJlYWtzPXN1YmxpbmVhZ2VzLmNvbHMuYnJldyRzdWJsaW5lYWdlKSArCiAgdGhlbWUudGV4dC5zaXplICsgdGhlbWUobGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjc1LCJsaW5lIiksbGVnZW5kLnBvc2l0aW9uPSdyaWdodCcpICsKICBnZW9tX3Jvb3RlZGdlKDAuMDAwMDAwNzUpIAoKcC5OaWNob2xzLnJlZi5zdWJ0cmVlLm5vZGVpZC50cmVlLmhtIDwtIHAuTmljaG9scy5yZWYuc3VidHJlZS5ub2RlaWQudHJlZS5obSArIG5ld19zY2FsZV9maWxsKCkKCgpwLk5pY2hvbHMucmVmLnN1YnRyZWUubm9kZWlkLnRyZWUuaG0gPC0gZ2hlYXRtYXAocC5OaWNob2xzLnJlZi5zdWJ0cmVlLm5vZGVpZC50cmVlLmhtLCBkYXRhLmZyYW1lKHJvdy5uYW1lcz1UUEEubWV0YTEuMi5waW5lY29uZSRTYW1wbGVfTmFtZSwgWWVhcj1UUEEubWV0YTEuMi5waW5lY29uZSRTYW1wbGVfNXllYXIud2luZG93LCBzdHJpbmdzQXNGYWN0b3JzID0gRiksIGNvbG9yPU5VTEwsd2lkdGg9MC4wNjUsb2Zmc2V0PTAuMDAwMDEzNSwgY29sbmFtZXNfYW5nbGU9MCxjb2xuYW1lc19vZmZzZXRfeT0tMC4wMSwgZm9udC5zaXplPTIpICsgc2NhbGVfZmlsbF9tYW51YWwobmFtZT0iWWVhciIsdmFsdWVzPVRQQS41eWVhci53aW5kb3cuYnJld2NvbHMkd2luZG93LjV5ZWFyLmNvbHNbMToobGVuZ3RoKFRQQS41eWVhci53aW5kb3cuYnJld2NvbHMkd2luZG93LjV5ZWFyLmNvbHMpLTEpXSwgYnJlYWtzPVRQQS41eWVhci53aW5kb3cuYnJld2NvbHMkd2luZG93LjV5ZWFyWzE6KGxlbmd0aChUUEEuNXllYXIud2luZG93LmJyZXdjb2xzJHdpbmRvdy41eWVhciktMSldKSAjKwogICN0aGVtZS50ZXh0LnNpemUgKyB0aGVtZShsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNzUsImxpbmUiKSxsZWdlbmQucG9zaXRpb249J2xlZnQnKQoKCnAuTmljaG9scy5yZWYuc3VidHJlZS5ub2RlaWQudHJlZS5obSA8LSBwLk5pY2hvbHMucmVmLnN1YnRyZWUubm9kZWlkLnRyZWUuaG0gKyBuZXdfc2NhbGVfZmlsbCgpCnAuTmljaG9scy5yZWYuc3VidHJlZS5ub2RlaWQudHJlZS5obQoKCmBgYAoKClBsb3QgbWFpbiBOaWNob2xzIHRyZWUsIGJ1dCB3aXRoIGhpZ2hsaWdodCBmb3IgcmVsZXZhbnQgY2xhZGUKYGBge3J9CnAuVFBBLk5pY2hvbHMuY29sbC5oaWdobGlnaHQgPC0gcC5UUEEuTmljaG9scy5jb2xsICsgbmV3X3NjYWxlX2ZpbGwoKQpwLlRQQS5OaWNob2xzLmNvbGwuaGlnaGxpZ2h0IDwtIHAuVFBBLk5pY2hvbHMuY29sbC5oaWdobGlnaHQgICsgZ2VvbV9oaWxpZ2h0KG5vZGU9TmljaG9scy5yZWYuc3VidHJlZS5ub2RlaWQsIGFscGhhPTAuMiwgZmlsbD0iZ3JleTQ1IikKI3AuVFBBLk5pY2hvbHMuY29sbC5oaWdobGlnaHQKCiMgQWRkIHNhbXBsZSB5ZWFyIChncm91cCkKcC5UUEEuTmljaG9scy5jb2xsLmhpZ2hsaWdodCA8LSBnaGVhdG1hcChwLlRQQS5OaWNob2xzLmNvbGwuaGlnaGxpZ2h0LGRhdGEuZnJhbWUocm93Lm5hbWVzPVRQQS5tZXRhMS4yLnBpbmVjb25lJFNhbXBsZV9OYW1lLCBZZWFyPVRQQS5tZXRhMS4yLnBpbmVjb25lJFNhbXBsZV81eWVhci53aW5kb3csIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKSwgY29sb3I9TlVMTCx3aWR0aD0wLjA4NSxvZmZzZXQ9MC4wMDAwMjAyNSwgY29sbmFtZXNfYW5nbGU9MCxjb2xuYW1lc19vZmZzZXRfeT0tMSwgZm9udC5zaXplPTIpICsgc2NhbGVfZmlsbF9tYW51YWwobmFtZT0iWWVhciIsdmFsdWVzPVRQQS41eWVhci53aW5kb3cuYnJld2NvbHMkd2luZG93LjV5ZWFyLmNvbHNbMToobGVuZ3RoKFRQQS41eWVhci53aW5kb3cuYnJld2NvbHMkd2luZG93LjV5ZWFyLmNvbHMpLTEpXSwgYnJlYWtzPVRQQS41eWVhci53aW5kb3cuYnJld2NvbHMkd2luZG93LjV5ZWFyWzE6KGxlbmd0aChUUEEuNXllYXIud2luZG93LmJyZXdjb2xzJHdpbmRvdy41eWVhciktMSldKSArCiAgdGhlbWUudGV4dC5zaXplICsgdGhlbWUobGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjY1LCJsaW5lIiksbGVnZW5kLnBvc2l0aW9uPSdsZWZ0JykKCnAuVFBBLk5pY2hvbHMuY29sbC5oaWdobGlnaHQgPC0gcC5UUEEuTmljaG9scy5jb2xsLmhpZ2hsaWdodCArIG5ld19zY2FsZV9maWxsKCkKYGBgCgoKCnBsb3QgTmljaG9scyB0cmVlcyB0b2dldGhlcgpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTcsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpwLk5pY2hvbHMucmVmLnN1YnRyZWUubm9kZWlkLnRyZWUuaG0uZ3JpZCA8LSBwbG90X2dyaWQoTlVMTCxwLk5pY2hvbHMucmVmLnN1YnRyZWUubm9kZWlkLnRyZWUuaG0gKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArIGdndGl0bGUoIlN1YnRyZWUiKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSksIE5VTEwsIHJlbF9oZWlnaHRzPWMoMSw0LDEpLG5jb2w9MSwgbGFiZWxzPWMoJycsJ0InLCcnKSwgbGFiZWxfc2l6ZT0xMSwgdmp1c3Q9MCkKCnAuTmljaG9scy5yZWYuc3VidHJlZS5ub2RlaWQudHJlZS5obS5ncmlkLmZpbmFsIDwtIHBsb3RfZ3JpZChwLlRQQS5OaWNob2xzLmNvbGwuaGlnaGxpZ2h0ICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJsZWZ0IikgKyBnZ3RpdGxlKCJOaWNob2xzLWxpbmVhZ2UgcGh5bG9nZW55IikgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpLE5VTEwscC5OaWNob2xzLnJlZi5zdWJ0cmVlLm5vZGVpZC50cmVlLmhtLmdyaWQsIG5jb2w9MywgcmVsX3dpZHRocz1jKDEwLDEsMTApLCBsYWJlbHM9YygnQScsJycsJycpLCB2anVzdD0xLCBsYWJlbF9zaXplPTExKQoKCiNDYWlybzo6Q2Fpcm8oZmlsZT1wYXN0ZTAoRmlndXJlX291dHB1dF9kaXJlY3RvcnksICJTdXBwbGVtZW50YXJ5X0ZpZ3VyZTZfTUx0cmVlX05pY2hvbHMtcmVmZXJlbmNlLWhpZ2hsaWdodF9fMDItMjAyMS5zdmciKSwgd2lkdGggPSA4MDAsIGhlaWdodCA9IDUwMCx0eXBlPSJzdmciLHVuaXRzID0gInB0IikKcC5OaWNob2xzLnJlZi5zdWJ0cmVlLm5vZGVpZC50cmVlLmhtLmdyaWQuZmluYWwKI2Rldi5vZmYoKQoKYGBgCgpzdWJzZXQgTmljaG9scyB0byBzaG93IG91dGdyb3VwcyBiZXR0ZXIKYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD04LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKIyBzdWJsaW5lYWdlIDE5IApzdWJsaW5lYWdlcy50b2NvbGxhcHNlLm5vZGVpZC4xOSA8LSA5OTcKIyBTdWJsaW5lYWdlIDE0IChmb3JtZXJseSBjYWxsZWQgMTkgaW4gb2xkZXIgYW5hbHlzaXMgYmVmb3JlIGJvb3RzdHJhcHBpbmcpCnN1YmxpbmVhZ2VzLnRvY29sbGFwc2Uubm9kZWlkLjE0IDwtIDk5NwoKIyBzdWJsaW5lYWdlIDEyIApzdWJsaW5lYWdlcy50b2NvbGxhcHNlLm5vZGVpZC4xMiA8LSA5NjMKCgoKIyBDb2xsYXBzZSBTUzE0IGNsYWRlIGFuZCBsYXJnZXN0IE5pY2hvbHMgc3VibGluZWFnZSB0byBtYWtlIGZvciBlYXNpZXIgdmlld2luZwpOaWNob2xzLmNvbGwuMmNsYWRlcyA8LSBnZ3RyZWUoVFBBLk1MdHJlZSkgJT4lIGNvbGxhcHNlKG5vZGU9U1MxNC5zdWJ0cmVlLm5vZGVpZCkgJT4lIAogIGNvbGxhcHNlKG5vZGU9c3VibGluZWFnZXMudG9jb2xsYXBzZS5ub2RlaWQuMTkpICMlPiUKICAjY29sbGFwc2Uobm9kZT1zdWJsaW5lYWdlcy50b2NvbGxhcHNlLm5vZGVpZC4xMikgCgojIEFkZCBzb21lIGV4dHJhIHRvIHkgYXhpcyBmb3Igc3BhY2luZwpOaWNob2xzLmNvbGwuMmNsYWRlcyRkYXRhW05pY2hvbHMuY29sbC4yY2xhZGVzJGRhdGEkbm9kZT09U1MxNC5zdWJ0cmVlLm5vZGVpZCwieSJdIDwtIE5pY2hvbHMuY29sbC4yY2xhZGVzJGRhdGFbTmljaG9scy5jb2xsLjJjbGFkZXMkZGF0YSRub2RlPT1TUzE0LnN1YnRyZWUubm9kZWlkLCJ5Il0gKyA4CgpOaWNob2xzLmNvbGwuMmNsYWRlcyRkYXRhW05pY2hvbHMuY29sbC4yY2xhZGVzJGRhdGEkbm9kZT09c3VibGluZWFnZXMudG9jb2xsYXBzZS5ub2RlaWQuMTQsInkiXSA8LSBOaWNob2xzLmNvbGwuMmNsYWRlcyRkYXRhW05pY2hvbHMuY29sbC4yY2xhZGVzJGRhdGEkbm9kZT09c3VibGluZWFnZXMudG9jb2xsYXBzZS5ub2RlaWQuMTQsInkiXSArIDMKCiNOaWNob2xzLmNvbGwuMmNsYWRlcyRkYXRhW05pY2hvbHMuY29sbC4yY2xhZGVzJGRhdGEkbm9kZT09c3VibGluZWFnZXMudG9jb2xsYXBzZS5ub2RlaWQuMTIsInkiXSA8LSBOaWNob2xzLmNvbGwuMmNsYWRlcyRkYXRhW05pY2hvbHMuY29sbC4yY2xhZGVzJGRhdGEkbm9kZT09c3VibGluZWFnZXMudG9jb2xsYXBzZS5ub2RlaWQuMTIsInkiXSArIDUKI3N1YmxpbmVhZ2VzLnRvY29sbGFwc2Uubm9kZWlkLjEyCgoKIyBBZGQgZmlyc3QgdHJpYW5nbGUKTmljaG9scy5jb2xsLjJjbGFkZXMgPC0gTmljaG9scy5jb2xsLjJjbGFkZXMgKyBnZW9tX3RleHQyKGFlcyhzdWJzZXQ9KG5vZGUgPT0gU1MxNC5zdWJ0cmVlLm5vZGVpZCkpLCBzaXplPTIwLCBsYWJlbD1pbnRUb1V0ZjgoOTY2NCksIGhqdXN0PTAuMix2anVzdD0uNTUsIGZhbWlseT0iT3BlblNhbnNFbW9qaSIsIGNvbG9yPSJpbmRpYW5yZWQxIiwgYWxwaGE9Ljc1KQpOaWNob2xzLmNvbGwuMmNsYWRlcyA8LSBOaWNob2xzLmNvbGwuMmNsYWRlcyAgKyBnZW9tX3RleHQyKGFlcyhzdWJzZXQ9KG5vZGUgPT0gU1MxNC5zdWJ0cmVlLm5vZGVpZCkpLCBjZXg9Mi41LCB2anVzdD0wLjIsIGxhYmVsPSJTUzE0IixoanVzdCA9IC0xLjUpCgoKIyBBZGQgc2Vjb25kIHRyaWFuZ2xlCiNOaWNob2xzLmNvbGwuMmNsYWRlcyA8LSBOaWNob2xzLmNvbGwuMmNsYWRlcyArIGdlb21fdGV4dDIoYWVzKHN1YnNldD0obm9kZSA9PSBzdWJsaW5lYWdlcy50b2NvbGxhcHNlLm5vZGVpZC4xOSkpLCBzaXplPTIwLCBsYWJlbD1pbnRUb1V0ZjgoOTY2NCksIGhqdXN0PTAuMix2anVzdD0uNTUsIGZhbWlseT0iT3BlblNhbnNFbW9qaSIsIGNvbG9yPXN1YmxpbmVhZ2VzLmNvbHMuYnJld1tzdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZT09MTksInN1YmxpbmVhZ2UuY29scyJdLCBhbHBoYT0uNzUpCiNOaWNob2xzLmNvbGwuMmNsYWRlcyA8LSBOaWNob2xzLmNvbGwuMmNsYWRlcyAgKyBnZW9tX3RleHQyKGFlcyhzdWJzZXQ9KG5vZGUgPT0gc3VibGluZWFnZXMudG9jb2xsYXBzZS5ub2RlaWQuMTkpKSwgY2V4PTIuNSwgdmp1c3Q9MC4yLCBsYWJlbD0iU3VibGluZWFnZSAxOSIsaGp1c3QgPSAtMC41KQoKTmljaG9scy5jb2xsLjJjbGFkZXMgPC0gTmljaG9scy5jb2xsLjJjbGFkZXMgKyBnZW9tX3RleHQyKGFlcyhzdWJzZXQ9KG5vZGUgPT0gc3VibGluZWFnZXMudG9jb2xsYXBzZS5ub2RlaWQuMTQpKSwgc2l6ZT0yMCwgbGFiZWw9aW50VG9VdGY4KDk2NjQpLCBoanVzdD0wLjIsdmp1c3Q9LjU1LCBmYW1pbHk9Ik9wZW5TYW5zRW1vamkiLCBjb2xvcj1zdWJsaW5lYWdlcy5jb2xzLmJyZXdbc3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2U9PTE0LCJzdWJsaW5lYWdlLmNvbHMiXSwgYWxwaGE9Ljc1KQpOaWNob2xzLmNvbGwuMmNsYWRlcyA8LSBOaWNob2xzLmNvbGwuMmNsYWRlcyAgKyBnZW9tX3RleHQyKGFlcyhzdWJzZXQ9KG5vZGUgPT0gc3VibGluZWFnZXMudG9jb2xsYXBzZS5ub2RlaWQuMTQpKSwgY2V4PTIuNSwgdmp1c3Q9MC4yLCBsYWJlbD0iU3VibGluZWFnZSAxNCIsaGp1c3QgPSAtMC41KQoKCgpwLk5pY2hvbHMuY29sbC4yY2xhZGVzIDwtIE5pY2hvbHMuY29sbC4yY2xhZGVzICU8KyUgZGF0YS5mcmFtZShTYW1wbGVfTmFtZT1UUEEubWV0YTEuMi5waW5lY29uZSRTYW1wbGVfTmFtZSwgU3VibGluZWFnZT1UUEEubWV0YTEuMi5waW5lY29uZSRUUEEucGluZWNvbmUuc3VibGluZWFnZSkgKwogIGdlb21fdGlwcG9pbnQoYWVzKGNvbG9yPVN1YmxpbmVhZ2UpLCBzaXplPTIuNSwgYWxwaGE9MC4yNSxzaG93LmxlZ2VuZD1GKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lPSJTdWJsaW5lYWdlIix2YWx1ZXM9c3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2UuY29scywgYnJlYWtzPXN1YmxpbmVhZ2VzLmNvbHMuYnJldyRzdWJsaW5lYWdlKSArCiAgIyBhZGQgYm9vdHN0cmFwIHN1cHBvcnQKICBnZW9tX3BvaW50MihhZXMoc3Vic2V0PSghaXNUaXAgJiBhcy5udW1lcmljKGxhYmVsKT45NSkpLHNpemU9Miwgc2hhcGU9MTgpICsKICBnZW9tX3RpcGxhYihzaXplPTIuNSxhbGlnbj1GKSArIAogIGdlb21fdHJlZXNjYWxlKGZvbnRzaXplID0gMi41LCB4PTAuMDAwMDEsIHk9MjUpICsgCiAgZ2VvbV90aXBsYWIoc2l6ZT0yLjUpICsgCiAgZ2VvbV9oaWxpZ2h0KG5vZGU9MTA1NSwgYWxwaGE9MC4yNSwgZmlsbD1zdWJsaW5lYWdlcy5jb2xzLmJyZXdbc3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2U9PTYsInN1YmxpbmVhZ2UuY29scyJdKSArCiAgZ2VvbV9oaWxpZ2h0KG5vZGU9OTU3LCBhbHBoYT0wLjI1LCBmaWxsPXN1YmxpbmVhZ2VzLmNvbHMuYnJld1tzdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZT09Nywic3VibGluZWFnZS5jb2xzIl0pCgpwLk5pY2hvbHMuY29sbC4yY2xhZGVzIDwtIHAuTmljaG9scy5jb2xsLjJjbGFkZXMgKyBuZXdfc2NhbGVfZmlsbCgpCgpwLk5pY2hvbHMuY29sbC4yY2xhZGVzLmhtIDwtIGdoZWF0bWFwKHAuTmljaG9scy5jb2xsLjJjbGFkZXMsCiAgICAgICAgICAgICAgIGRhdGEuZnJhbWUocm93Lm5hbWVzPVRQQS5tZXRhMS4yLnBpbmVjb25lJFNhbXBsZV9OYW1lLCBTdWJsaW5lYWdlPVRQQS5tZXRhMS4yLnBpbmVjb25lJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlKSwgY29sb3I9TlVMTCx3aWR0aD0wLjA2LG9mZnNldD0wLjAwMDAwOTUsIGNvbG5hbWVzX2FuZ2xlPTAsY29sbmFtZXNfb2Zmc2V0X3k9LTAuMDEsIGZvbnQuc2l6ZT0yLjI1KSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWU9IlN1YmxpbmVhZ2UiLHZhbHVlcz1zdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZS5jb2xzLCBicmVha3M9c3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2UpICsKICB0aGVtZS50ZXh0LnNpemUgKyB0aGVtZShsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNjUsImxpbmUiKSxsZWdlbmQucG9zaXRpb249J3JpZ2h0JykKCnAuTmljaG9scy5jb2xsLjJjbGFkZXMuaG0gPC0gcC5OaWNob2xzLmNvbGwuMmNsYWRlcy5obSArIG5ld19zY2FsZV9maWxsKCkKCnAuTmljaG9scy5jb2xsLjJjbGFkZXMuaG0gPC0gZ2hlYXRtYXAocC5OaWNob2xzLmNvbGwuMmNsYWRlcy5obSxUUEEucmF3c2VxLmNvdW50cmllcy5wLCBjb2xvcj1OVUxMLHdpZHRoPTAuMDYsb2Zmc2V0PTAuMDAwMDE2NSwgY29sbmFtZXNfYW5nbGU9MCxjb2xuYW1lc19vZmZzZXRfeT0tMC4wMSwgZm9udC5zaXplPTIuMjUpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZT0iQ291bnRyeSIsdmFsdWVzPWNvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MiRjb3VudHJ5LmNvbCwgYnJlYWtzPWNvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MiRHZW9fQ291bnRyeSkgKwogIHRoZW1lLnRleHQuc2l6ZSArIHRoZW1lKGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC42NSwibGluZSIpLGxlZ2VuZC5wb3NpdGlvbj0nYm90dG9tJykgKyAKICAjZ2VvbV90cmVlc2NhbGUoZm9udHNpemUgPSAyLjUsIHg9MC4wMDAwMDEsIHk9MzUpICsKICBOVUxMCnAuTmljaG9scy5jb2xsLjJjbGFkZXMuaG0gPC0gcC5OaWNob2xzLmNvbGwuMmNsYWRlcy5obSArIG5ld19zY2FsZV9maWxsKCkKCgpwLk5pY2hvbHMuY29sbC4yY2xhZGVzLmhtIDwtIGdoZWF0bWFwKHAuTmljaG9scy5jb2xsLjJjbGFkZXMuaG0sIGRhdGEuZnJhbWUocm93Lm5hbWVzPVRQQS5tZXRhMS4yLnBpbmVjb25lJFNhbXBsZV9OYW1lLCBZZWFyPVRQQS5tZXRhMS4yLnBpbmVjb25lJFNhbXBsZV81eWVhci53aW5kb3csIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKSwgY29sb3I9TlVMTCx3aWR0aD0wLjA2LG9mZnNldD0wLjAwMDAyMzUsIGNvbG5hbWVzX2FuZ2xlPTAsY29sbmFtZXNfb2Zmc2V0X3k9LTAuMDEsIGZvbnQuc2l6ZT0yLjI1KSArIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWU9IlllYXIiLHZhbHVlcz1UUEEuNXllYXIud2luZG93LmJyZXdjb2xzJHdpbmRvdy41eWVhci5jb2xzWzE6KGxlbmd0aChUUEEuNXllYXIud2luZG93LmJyZXdjb2xzJHdpbmRvdy41eWVhci5jb2xzKS0xKV0sIGJyZWFrcz1UUEEuNXllYXIud2luZG93LmJyZXdjb2xzJHdpbmRvdy41eWVhclsxOihsZW5ndGgoVFBBLjV5ZWFyLndpbmRvdy5icmV3Y29scyR3aW5kb3cuNXllYXIpLTEpXSkgKwogIHRoZW1lLnRleHQuc2l6ZSArIHRoZW1lKGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC42NSwibGluZSIpLGxlZ2VuZC5wb3NpdGlvbj0nbGVmdCcpICsgCiAgeWxpbSgtMSw1NykKCnAuVFBBLk5pY2hvbHMuY29sbC5oaWdobGlnaHQgPC0gcC5UUEEuTmljaG9scy5jb2xsLmhpZ2hsaWdodCArIG5ld19zY2FsZV9maWxsKCkKCgoKI0NhaXJvOjpDYWlybyhmaWxlPXBhc3RlMChGaWd1cmVfb3V0cHV0X2RpcmVjdG9yeSwgIlN1cHBsZW1lbnRhcnlfRmlndXJlNV9NTHRyZWVfaGlnaGxpZ2h0LW91dGdyb3Vwc19fMDItMjAyMS5zdmciKSwgd2lkdGggPSA3MDAsIGhlaWdodCA9IDUwMCx0eXBlPSJzdmciLHVuaXRzID0gInB0IikKcC5OaWNob2xzLmNvbGwuMmNsYWRlcy5obSArIGdndGl0bGUoIk5pY2hvbHMtbGluZWFnZSBwaHlsb2dlbnkgd2l0aCBjb2xsYXBzZWQgbm9kZXMiKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkKI2Rldi5vZmYoKQpgYGAKCgoKU3Vic2V0IFNTMTQgdHJlZSB0byBzaG93IG91dGdyb3VwcwpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9OCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCiNTUzE0LmNvbGwgKyBnZW9tX3RleHQyKGFlcyhzdWJzZXQ9IWlzVGlwLCBsYWJlbD1ub2RlKSwgaGp1c3Q9LS4zLCBzaXplPTIuNSkKCiNzczE0LnN1YmxpbjIuY29sbGFwc2Uubm9kZSA8LSA1NDIKc3MxNC5zdWJsaW4xLmNvbGxhcHNlLm5vZGUgPC0gNTM0ICM1MzUKClNTMTQuc3ViY2xhZGVzMSA8LSBnZ3RyZWUoVFBBLk1MdHJlZSkgJT4lIGNvbGxhcHNlKG5vZGU9TmljaG9scy5zdWJ0cmVlLm5vZGVpZCkgJT4lIAogIGNvbGxhcHNlKG5vZGU9c3MxNC5zdWJsaW4xLmNvbGxhcHNlLm5vZGUpCiMgQWRkIHNvbWUgZXh0cmEgdG8geSBheGlzIGZvciBzcGFjaW5nClNTMTQuc3ViY2xhZGVzMSRkYXRhW1NTMTQuc3ViY2xhZGVzMSRkYXRhJG5vZGU9PU5pY2hvbHMuc3VidHJlZS5ub2RlaWQsInkiXSA8LSBTUzE0LnN1YmNsYWRlczEkZGF0YVtTUzE0LnN1YmNsYWRlczEkZGF0YSRub2RlPT1OaWNob2xzLnN1YnRyZWUubm9kZWlkLCJ5Il0gLTUKClNTMTQuc3ViY2xhZGVzMSRkYXRhW1NTMTQuc3ViY2xhZGVzMSRkYXRhJG5vZGU9PXNzMTQuc3VibGluMS5jb2xsYXBzZS5ub2RlLCJ5Il0gPC0gU1MxNC5zdWJjbGFkZXMxJGRhdGFbU1MxNC5zdWJjbGFkZXMxJGRhdGEkbm9kZT09c3MxNC5zdWJsaW4xLmNvbGxhcHNlLm5vZGUsInkiXSArIDIKCiMgQWRkIGZpcnN0IHRyaWFuZ2xlClNTMTQuc3ViY2xhZGVzMSA8LSBTUzE0LnN1YmNsYWRlczEgKyBnZW9tX3RleHQyKGFlcyhzdWJzZXQ9KG5vZGUgPT0gTmljaG9scy5zdWJ0cmVlLm5vZGVpZCkpLCBzaXplPTIwLCBsYWJlbD1pbnRUb1V0ZjgoOTY2NCksIGhqdXN0PTAuMix2anVzdD0uNTUsIGZhbWlseT0iT3BlblNhbnNFbW9qaSIsIGNvbG9yPSJyb3lhbGJsdWUyIiwgYWxwaGE9Ljc1KQpTUzE0LnN1YmNsYWRlczEgPC0gU1MxNC5zdWJjbGFkZXMxICsgZ2VvbV90ZXh0MihhZXMoc3Vic2V0PShub2RlID09IE5pY2hvbHMuc3VidHJlZS5ub2RlaWQpKSwgY2V4PTIuNSwgdmp1c3Q9MC4yLCBsYWJlbD0iTmljaG9scyIsaGp1c3QgPSAtMS4yNSkKIyBBZGQgc2Vjb25kIHRyaWFuZ2xlClNTMTQuc3ViY2xhZGVzMSA8LSBTUzE0LnN1YmNsYWRlczEgKyBnZW9tX3RleHQyKGFlcyhzdWJzZXQ9KG5vZGUgPT0gc3MxNC5zdWJsaW4xLmNvbGxhcHNlLm5vZGUpKSwgc2l6ZT0yMCwgbGFiZWw9aW50VG9VdGY4KDk2NjQpLCBoanVzdD0wLjIsdmp1c3Q9LjU1LCBmYW1pbHk9Ik9wZW5TYW5zRW1vamkiLCBjb2xvcj1zdWJsaW5lYWdlcy5jb2xzLmJyZXdbc3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2U9PTEsInN1YmxpbmVhZ2UuY29scyJdLCBhbHBoYT0uNzUpClNTMTQuc3ViY2xhZGVzMSA8LSBTUzE0LnN1YmNsYWRlczEgKyBnZW9tX3RleHQyKGFlcyhzdWJzZXQ9KG5vZGUgPT0gc3MxNC5zdWJsaW4xLmNvbGxhcHNlLm5vZGUpKSwgY2V4PTIsIHZqdXN0PTAuMiwgbGFiZWw9IlN1YmxpbmVhZ2UgMSIsaGp1c3QgPSAtMC43NSkKCgojIGFkZCB0aXBwb2ludCBjb2xvdXJzIChzdWJsaW5lYWdlKQpwLlNTMTQuc3ViY2xhZGVzMSA8LSBTUzE0LnN1YmNsYWRlczEgJTwrJSBkYXRhLmZyYW1lKFNhbXBsZV9OYW1lPVRQQS5tZXRhMS4yLnBpbmVjb25lJFNhbXBsZV9OYW1lLCBTdWJsaW5lYWdlPVRQQS5tZXRhMS4yLnBpbmVjb25lJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlKSArCiAgZ2VvbV90aXBwb2ludChhZXMoY29sb3I9U3VibGluZWFnZSksIHNpemU9MS41LCBhbHBoYT0wLjI1LHNob3cubGVnZW5kPUYpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWU9IlN1YmxpbmVhZ2UiLHZhbHVlcz1zdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZS5jb2xzLCBicmVha3M9c3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2UpICsKICAjIGFkZCBib290c3RyYXAgc3VwcG9ydAogIGdlb21fcG9pbnQyKGFlcyhzdWJzZXQ9KCFpc1RpcCAmIGFzLm51bWVyaWMobGFiZWwpPjk1KSksc2l6ZT0yLCBzaGFwZT0xOCkgKwogIGdlb21fdHJlZXNjYWxlKGZvbnRzaXplID0gMi41LCB4PTAuMDAwMDEsIHk9MjUpICAKcC5TUzE0LnN1YmNsYWRlczEgPC0gcC5TUzE0LnN1YmNsYWRlczEgKyBuZXdfc2NhbGVfZmlsbCgpCgojIGFkZCBoZWF0bWFwIHN0cmlwcyAoc3VibGluZWFnZSkKcC5TUzE0LnN1YmNsYWRlczEuaG0gPC0gZ2hlYXRtYXAocC5TUzE0LnN1YmNsYWRlczEsCiAgICAgICAgICAgICAgIGRhdGEuZnJhbWUocm93Lm5hbWVzPVRQQS5tZXRhMS4yLnBpbmVjb25lJFNhbXBsZV9OYW1lLCBTdWJsaW5lYWdlPVRQQS5tZXRhMS4yLnBpbmVjb25lJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlKSwgY29sb3I9TlVMTCx3aWR0aD0wLjA2LG9mZnNldD0wLjAwMDAwOTUsIGNvbG5hbWVzX2FuZ2xlPTAsY29sbmFtZXNfb2Zmc2V0X3k9LTAuMDEsIGZvbnQuc2l6ZT0yLjI1KSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWU9IlN1YmxpbmVhZ2UiLHZhbHVlcz1zdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZS5jb2xzLCBicmVha3M9c3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2UpICsKICB0aGVtZS50ZXh0LnNpemUgKyB0aGVtZShsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNjUsImxpbmUiKSxsZWdlbmQucG9zaXRpb249J3JpZ2h0JykKcC5TUzE0LnN1YmNsYWRlczEuaG0gPC0gcC5TUzE0LnN1YmNsYWRlczEuaG0gKyBuZXdfc2NhbGVfZmlsbCgpCgojIGFkZCBoZWF0bWFwIHN0cmlwcyAoY291bnRyeSkKcC5TUzE0LnN1YmNsYWRlczEuaG0gPC0gZ2hlYXRtYXAocC5TUzE0LnN1YmNsYWRlczEuaG0sVFBBLnJhd3NlcS5jb3VudHJpZXMucCwgY29sb3I9TlVMTCx3aWR0aD0wLjA2LG9mZnNldD0wLjAwMDAxNTUsIGNvbG5hbWVzX2FuZ2xlPTAsY29sbmFtZXNfb2Zmc2V0X3k9LTAuMDEsIGZvbnQuc2l6ZT0yLjI1KSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWU9IkNvdW50cnkiLHZhbHVlcz1jb250aW5lbnRhbC5jb3VudHJ5LmNvbHMuYnJldzIkY291bnRyeS5jb2wsIGJyZWFrcz1jb250aW5lbnRhbC5jb3VudHJ5LmNvbHMuYnJldzIkR2VvX0NvdW50cnkpICsKICB0aGVtZS50ZXh0LnNpemUgKyB0aGVtZShsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNjUsImxpbmUiKSxsZWdlbmQucG9zaXRpb249J2JvdHRvbScpICsKICBnZW9tX3RpcGxhYihzaXplPTIpICsKICBOVUxMCnAuU1MxNC5zdWJjbGFkZXMxLmhtIDwtIHAuU1MxNC5zdWJjbGFkZXMxLmhtICsgbmV3X3NjYWxlX2ZpbGwoKQoKIyBBZGQgeWVhciBncm91cApwLlNTMTQuc3ViY2xhZGVzMS5obSA8LSBnaGVhdG1hcChwLlNTMTQuc3ViY2xhZGVzMS5obSxkYXRhLmZyYW1lKHJvdy5uYW1lcz1UUEEubWV0YTEuMi5waW5lY29uZSRTYW1wbGVfTmFtZSwgWWVhcj1UUEEubWV0YTEuMi5waW5lY29uZSRTYW1wbGVfNXllYXIud2luZG93LCBzdHJpbmdzQXNGYWN0b3JzID0gRiksIGNvbG9yPU5VTEwsd2lkdGg9MC4wNjUsb2Zmc2V0PTAuMDAwMDIxNSwgY29sbmFtZXNfYW5nbGU9MCxjb2xuYW1lc19vZmZzZXRfeT0tMC4wMSwgZm9udC5zaXplPTIuMjUpICsgc2NhbGVfZmlsbF9tYW51YWwobmFtZT0iWWVhciIsdmFsdWVzPVRQQS41eWVhci53aW5kb3cuYnJld2NvbHMkd2luZG93LjV5ZWFyLmNvbHNbMToobGVuZ3RoKFRQQS41eWVhci53aW5kb3cuYnJld2NvbHMkd2luZG93LjV5ZWFyLmNvbHMpLTEpXSwgYnJlYWtzPVRQQS41eWVhci53aW5kb3cuYnJld2NvbHMkd2luZG93LjV5ZWFyWzE6KGxlbmd0aChUUEEuNXllYXIud2luZG93LmJyZXdjb2xzJHdpbmRvdy41eWVhciktMSldKSArCiAgdGhlbWUudGV4dC5zaXplICsgdGhlbWUobGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjY1LCJsaW5lIiksbGVnZW5kLnBvc2l0aW9uPSdsZWZ0JykgKwogIHlsaW0oLTYsNjcpICN5bGltKC02LDExNSkgIApwLlNTMTQuc3ViY2xhZGVzMS5obSA8LSBwLlNTMTQuc3ViY2xhZGVzMS5obSArIG5ld19zY2FsZV9maWxsKCkKCgojQ2Fpcm86OkNhaXJvKGZpbGU9cGFzdGUwKEZpZ3VyZV9vdXRwdXRfZGlyZWN0b3J5LCAiU3VwcGxlbWVudGFyeV9GaWd1cmU0X01MdHJlZV9oaWdobGlnaHQtU1MxNF9fMDItMjAyMS5zdmciKSwgd2lkdGggPSA3MDAsIGhlaWdodCA9IDgwMCx0eXBlPSJzdmciLHVuaXRzID0gInB0IikKcC5TUzE0LnN1YmNsYWRlczEuaG0gKyBnZ3RpdGxlKCJTUzE0LWxpbmVhZ2UgcGh5bG9nZW55IikgKyB0aGVtZShwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChzaXplID0gMTApKQojZGV2Lm9mZigpCgpgYGAKCgpcClwKXAoKCiMjIyBCRUFTVCBhbmFseXNpcyBcClwKXApTdWJzYW1wbGluZyByZXByZXNlbnRhdGl2ZSB0cmVlIGZvciBCRUFTVCBhbmFseWlzCgpgYGB7cn0KCkNvdW50cnkubGlzdDIgPC0gZGF0YS5mcmFtZShjb250aW5lbnRhbC5jb3VudHJ5LmNvbHMuYnJldzIsc3RyaW5nc0FzRmFjdG9ycyA9IEYpW2NvbnRpbmVudGFsLmNvdW50cnkuY29scy5icmV3MiRHZW9fQ291bnRyeSE9IkJlbGdpdW0iLCJHZW9fQ291bnRyeSJdCnN1YmxpbmVhZ2UubGluZWFnZS5saXN0MiA8LSBzdWJsaW5lYWdlcy5jb2xzLmJyZXdbc3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2UhPSJTaW5nbGV0b24iLCJzdWJsaW5lYWdlIl0KI0Z1bGwuc2FtcGxlbGlzdDIgPC0gVFBBLm1ldGExLjIucGluZWNvbmUkU2FtcGxlX05hbWUKRnVsbC5zYW1wbGVsaXN0MiA8LSBUUEEubWV0YTEuMi5waW5lY29uZVsoKFRQQS5tZXRhMS4yLnBpbmVjb25lJFNhbXBsZV9ZZWFyIT0iLSIpICYgIWdyZXBsKCJOaWNob2xzIixUUEEubWV0YTEuMi5waW5lY29uZSRTYW1wbGVfTmFtZSkgJiAhZ3JlcGwoIi0iLFRQQS5tZXRhMS4yLnBpbmVjb25lJFNhbXBsZV9ZZWFyKSksIlNhbXBsZV9OYW1lIl0KVFBBLm1ldGExLjIucGluZWNvbmUuaGF2ZWRhdGVzIDwtIFRQQS5tZXRhMS4yLnBpbmVjb25lW1RQQS5tZXRhMS4yLnBpbmVjb25lJFNhbXBsZV9OYW1lICVpbiUgRnVsbC5zYW1wbGVsaXN0MixdCgoKbXlzYW1wbGVzaXplIDwtIDUKdG90YWwuYm9vdHN0cmFwcyA8LSAxCgphbGwuYm9vdHN0cmFwcy5saXN0cyA8LSBOVUxMCmFsbC5ib290c3RyYXBzLnRyZWVzIDwtIGMocnRyZWUoMjApKSAjIGNyZWF0ZSB3aXRoIHJhbmRvbSBzdGFydCB0cmVlIHRvIGZvcmNlIGludG8gYSBtdWx0aXBoeWxvIG9iamVjdApjdXJyZW50LmJvb3RzdHJhcCA8LSAwCnJlcGVhdCB7CiAgY291bnRyeS5zYW1wbGUgPC0gTlVMTAogIGZvciAoY3VycmVudC5saW5lYWdlIGluIHN1YmxpbmVhZ2UubGluZWFnZS5saXN0Mil7CiAgICBmb3IgKGN1cnJlbnQuY291bnRyeSBpbiBDb3VudHJ5Lmxpc3QyKXsKICAgICAgY3VycmVudC5saXN0IDwtIFRQQS5tZXRhMS4yLnBpbmVjb25lLmhhdmVkYXRlc1soVFBBLm1ldGExLjIucGluZWNvbmUuaGF2ZWRhdGVzJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlPT1jdXJyZW50LmxpbmVhZ2UgJiBUUEEubWV0YTEuMi5waW5lY29uZS5oYXZlZGF0ZXMkR2VvX0NvdW50cnk9PWN1cnJlbnQuY291bnRyeSksIlNhbXBsZV9OYW1lIl0KICAgICAgY3VycmVudC5saXN0IDwtIGN1cnJlbnQubGlzdFshaXMubmEoY3VycmVudC5saXN0KV0KICAgICAgaWYgKGxlbmd0aChjdXJyZW50Lmxpc3QpPjEpewogICAgICAgIGN1cnJlbnQuc2FtcGxlIDwtIHVuaXF1ZShzYW1wbGUoY3VycmVudC5saXN0LHNpemU9bXlzYW1wbGVzaXplLCByZXBsYWNlPVQpKQogICAgICAgIGNvdW50cnkuc2FtcGxlIDwtIGMoYXMudmVjdG9yKGN1cnJlbnQuc2FtcGxlKSwgY291bnRyeS5zYW1wbGUpCiAgICAgIH0KICAgIH0KICB9CiAgY291bnRyeS5zYW1wbGUgPC0gYyhjb3VudHJ5LnNhbXBsZSwgYXMudmVjdG9yKFRQQS5tZXRhMS4yLnBpbmVjb25lLmhhdmVkYXRlc1soVFBBLm1ldGExLjIucGluZWNvbmUuaGF2ZWRhdGVzJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlPT0iU2luZ2xldG9uIiksIlNhbXBsZV9OYW1lIl0pKQogIAogIGN1cnJlbnQuYm9vdHN0cmFwIDwtIGN1cnJlbnQuYm9vdHN0cmFwICsgMQogIGN1cnJlbnQuc2FtcGxlLnRyZWUgPC0gKGFwZTo6a2VlcC50aXAoVFBBLk1MdHJlZSwgY291bnRyeS5zYW1wbGUpKQogIGFsbC5ib290c3RyYXBzLnRyZWVzIDwtIGMoYWxsLmJvb3RzdHJhcHMudHJlZXMsYyhjdXJyZW50LnNhbXBsZS50cmVlKSxyZWN1cnNpdmU9VCkKICBhbGwuYm9vdHN0cmFwcy5saXN0cyA8LSBjKGFsbC5ib290c3RyYXBzLmxpc3RzLCBsaXN0KGNvdW50cnkuc2FtcGxlKSkKICBpZiAoY3VycmVudC5ib290c3RyYXAgPT0gdG90YWwuYm9vdHN0cmFwcyl7CiAgICBicmVhawogIH0KfQphbGwuYm9vdHN0cmFwcy50cmVlcyA8LSBhbGwuYm9vdHN0cmFwcy50cmVlc1tjKDI6KHRvdGFsLmJvb3RzdHJhcHMrMSkpXSAjIHJlbW92ZSByYW5kb20gc3RhcnQgdHJlZQoKI2FsbC5ib290c3RyYXBzLnRyZWVzW1sxXV0KI3N1YnNhbXBsZWQuTUwudGlwcy42cENvdW50cnkucFN1YmxpbiA8LSBhbGwuYm9vdHN0cmFwcy50cmVlc1tbMV1dJHRpcC5sYWJlbAoKIyBPdXRwdXRzIGZyb20gYSBwcmV2aW91cyByYW5kb20gbG9vcCB1c2VkIGJlbG93IHRvIGVuc3VyZSBzYW1wbGUgcmVtYWlucyB0aGUgc2FtZQpzdWJzYW1wbGVkLk1MLnRpcHMuNnBDb3VudHJ5LnBTdWJsaW4gPC0gYygiTWV4aWNvX0EtbWNmIiwgIlRQQV9SVVNfVHV2YS02MiIsICJUUEFfUlVTX1R1dmEtNTgiLCAiVFBBX1JVU19UdXZhLTU5IiwgIlRQQV9SVVNfVHV2YS02MSIsICJQSEUxNDAwNzNBIiwgIlVXMTE2QiIsICJVVzE4NkIiLCAiVVcyMTNCIiwgIlBIRTE1MDEzN0EiLCAiUEhFMTUwMTI5QSIsICJUUEFfVUtCUkcwMTciLCAiVFBBX0JDQzE2MSIsICJUUEFfT01JMDA2IiwgIlRQQV9BTEMxMDUiLCAiVVcxODdCIiwgIlBIRTE1MDE3N0EiLCAiVFBBX0JDQzA4NSIsICJLMyIsICJTSEVfViIsICJDMyIsICJRMyIsICJUUEFfQkNDMDc1IiwgIlRQQV9VU0wtQkFMLTIiLCAiU1MxNF92MiIsICJVVzgyNEIiLCAiUEhFMTQwMDg0QSIsICJUUEFfSFVOMjAwMDI0IiwgIlRQQV9IVU4xOTAwMjIiLCAiVFBBX1VLQlJHMDA0IiwgIlRQQV9IVU4xOTAwMDgiLCAiVVcwOTlCIiwgIlRQQV9VU0wtU0VBLTgxLTgiLCAiVFBBX1pJTTAyNSIsICJUUEFfWklNMDA1IiwgIlRQQV9aSU0wMDkiLCAiVFBBX1pJTTAwNyIsICJVVzI2MkIiLCAiVVczOTFCIiwgIlRQQV9CQ0MxMzkiLCAiVFBBX0JDQzEzNyIsICJUUEFfVUtCUkcwMTUiLCAiVFBBX1VLQlJHMDE4IiwgIlBIRTEzMDA0MUEiLCAiVFBBX0JDQzEzMCIsICJVVzM3NkIiLCAiUEhFMTUwMTU5QSIsICJVVzI0NEIiLCAiVVcyOTFCIiwgIlRQQV9CQ0MxMjUiLCAiUFRfU0lGMTAwMiIsICJQVF9TSUYxMTk2IiwgIlBUX1NJRjA4NTciLCAiUEhFMTYwMjU0QSIsICJQVF9TSUYxMTgzIiwgIlBIRTE2MDI0OUEiLCAiUEhFMTcwMzc5QSIsICJQVF9TSUYxMDIwIiwgIlBUX1NJRjEwNjMiLCAiUEhFMTYwMzE1QSIsICJQSEUxNzAzOThBIiwgIlBIRTE3MDM4MEEiLCAiUEhFMTcwMzY1QSIsICJVVzE0OEIiLCAiVVc0NzNCIiwgIlVXNDkyQiIsICJVVzI0OEIiLCAiVFBBX0hVTjE5MDAyMyIsICJVVzEzOEIiLCAiVVczNjhCIiwgIlVXMTQ5QiIsICJVVzEwNEIiLCAiU01VVHBfMDIiLCAiU01VVHBfMDEiLCAiU01VVHBfMDgiLCAiUFRfU0lGMDk1NCIsICJQVF9TSUYxMjAwIiwgIlRQQV9CQ0MxMjgiLCAiVFBBX0JDQzEyNyIsICJUUEFfQVVTQlItNDUiLCAiVFBBX0hVTjE4MDAwNyIsICJQSEUxNjAyNDZBIiwgIlVXMzI3QiIsICJDVzg3IiwgIlRQQV9FU0JDTjAwMiIsICJUUEFfU1dFLTQ2NyIsICJUUEFfRUlSMDE3IiwgIlRQQV9IVU4xOTAwMTciLCAiUEhFMTYwMjQ4QSIsICJQSEUxMzAwNTNBIiwgIlRQQV9IVU4xODAwMDEiLCAiVFBBX1NXRS02NjIiLCAiUEhFMTMwMDUxQSIsICJUUEFfQkNDMTM4IiwgIlRQQV9BVVNCUi0xMTMiLCAiVFBBX1NXRS0xMzUyIiwgIlBUX1NJRjA4NzdfMyIsICJQVF9TSUYxMTQyIiwgIlRQQV9FSVIwMTMiLCAiQVUxNSIsICJUUEFfRUlSMDA4IiwgIkFVMTYiLCAiVFBBX0JDQzA0OSIsICJDVzg0IiwgIlRQQV9CQ0MwNTIiLCAiUEhFMTcwMzkyQSIsICJTZWF0dGxlXzgxLTQiLCAiVFBBX1VTTC1TRUEtODMtMiIsICJVVzI3OUIiLCAiVFBBX1VTTC1TRUEtODYtMSIsICJQSEUxNzAzMzZCIiwgIlBIRTE1MDExNEEiLCAiVFBBX09NSTAyMSIsICJDVzU5IiwgIkNXODIiLCAiVFBBX1VTTC1QaGlsLTMiLCAiQkFMMyIsICJCQUw3MyIsICJUUEFfWklNMDE0IiwgIlRQQV9aSU0wMTgiLCAiVFBBX1pJTTAxNSIsICJQSEUxNTAxNjZBIiwgIlBIRTE2MDMwNkEiLCAiUEhFMTUwMTY4QSIsICJUUEFfQkNDMTIyIiwgIlBIRTE2MDI5NEEiLCAiVFBBX0hVTjE4MDAwNCIsICJUUEFfQkNDMTM2IiwgIlRQQV9IVU4xOTAwMjAiLCAiUEhFMTYwMjg3QSIsICJUUEFfQkNDMTI2IiwgIlRQQV9CQ0MxNjkiLCAiVFBBX0JDQzAxMiIsICJQSEUxMjAwMjlBIiwgIlBIRTEyMDAzM0EiLCAiVFBBX1VTTC1IYWl0aS1CIiwgIlBIRTE2MDI4M0EiLCAiUEhFMTMwMDQ4QSIpCgoKCnN1YnNhbXBsZWQuTUwudGlwcy42cENvdW50cnkucFN1Ymxpbi50cmVlIDwtIChhcGU6OmtlZXAudGlwKFRQQS5NTHRyZWUsIHN1YnNhbXBsZWQuTUwudGlwcy42cENvdW50cnkucFN1YmxpbikpCgpzdWJzYW1wbGVkLk1MLnRpcHMuNnBDb3VudHJ5LnBTdWJsaW4udHJlZS5kYXRhIDwtIGRhdGEuZnJhbWUoZm9ydGlmeShzdWJzYW1wbGVkLk1MLnRpcHMuNnBDb3VudHJ5LnBTdWJsaW4udHJlZSksc3RyaW5nc0FzRmFjdG9ycyA9IEYpCnN1YnNhbXBsZWQuTUwudGlwcy42cENvdW50cnkucFN1Ymxpbi50cmVlLmRhdGEkU2FtcGxlX05hbWUgPC0gc3Vic2FtcGxlZC5NTC50aXBzLjZwQ291bnRyeS5wU3VibGluLnRyZWUuZGF0YSRsYWJlbCAKc3Vic2FtcGxlZC5NTC50aXBzLjZwQ291bnRyeS5wU3VibGluLnRyZWUuZGF0YSA8LSBwbHlyOjpqb2luKHN1YnNhbXBsZWQuTUwudGlwcy42cENvdW50cnkucFN1Ymxpbi50cmVlLmRhdGEsIFRQQS5tZXRhMS4yLnBpbmVjb25lLmhhdmVkYXRlc1ssYygiU2FtcGxlX05hbWUiLCJUUEEucGluZWNvbmUubWFqb3IiLCJUUEEucGluZWNvbmUuc3VibGluZWFnZSIsICJTYW1wbGVfWWVhciIpXSwgYnk9IlNhbXBsZV9OYW1lIiwgdHlwZT0ibGVmdCIpCgoKCgpwbG90LnN1YnNhbXBsZWQuTUwudGlwcy42cENvdW50cnkucFN1Ymxpbi50cmVlIDwtIGdndHJlZShzdWJzYW1wbGVkLk1MLnRpcHMuNnBDb3VudHJ5LnBTdWJsaW4udHJlZSkgJTwrJSBkYXRhLmZyYW1lKFNhbXBsZV9OYW1lPVRQQS5tZXRhMS4yLnBpbmVjb25lJFNhbXBsZV9OYW1lLCBTdWJsaW5lYWdlPVRQQS5tZXRhMS4yLnBpbmVjb25lJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlKSArIAogIGdlb21fdGlwcG9pbnQoYWVzKGNvbG9yPVN1YmxpbmVhZ2UpLCBzaXplPTEsIGFscGhhPTAuNSkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZT0iU3VibGluZWFnZSIsdmFsdWVzPXN1YmxpbmVhZ2VzLmNvbHMuYnJldyRzdWJsaW5lYWdlLmNvbHMsIGJyZWFrcz1zdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZSkgCgpwbG90LnN1YnNhbXBsZWQuTUwudGlwcy42cENvdW50cnkucFN1Ymxpbi50cmVlIDwtIGdoZWF0bWFwKHBsb3Quc3Vic2FtcGxlZC5NTC50aXBzLjZwQ291bnRyeS5wU3VibGluLnRyZWUsCiAgICAgICAgICAgICAgIGRhdGEuZnJhbWUocm93Lm5hbWVzPVRQQS5tZXRhMS4yLnBpbmVjb25lJFNhbXBsZV9OYW1lLCBTdWJsaW5lYWdlPVRQQS5tZXRhMS4yLnBpbmVjb25lJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlKSwgY29sb3I9TlVMTCx3aWR0aD0wLjA0LCBjb2xuYW1lc19hbmdsZT0wLGNvbG5hbWVzX29mZnNldF95PS0xLCBmb250LnNpemU9Mi41KSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWU9IlN1YmxpbmVhZ2UiLHZhbHVlcz1zdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZS5jb2xzLCBicmVha3M9c3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2UpICsKICB0aGVtZS50ZXh0LnNpemUgKyB0aGVtZShsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNSwibGluZSIpKQoKYGBgCgpwbG90IHN1YnNhbXBsZWQgTUwgc3VidHJlZQpgYGB7cn0KcGxvdC5zdWJzYW1wbGVkLk1MLnRpcHMuNnBDb3VudHJ5LnBTdWJsaW4udHJlZQpgYGAKCkRlZmluZSBmdW5jdGlvbiB0byBleHRyYWN0IGFuZCBwbG90IHJvb3QtMi10aXAgZGF0YSBmcm9tIGEgdHJlZSBvciBzdWJ0cmVlCmBgYHtyfQojIElucHV0cwojIC0gQSBtYXhpbXVtIGxpa2VsaWhvb2QgdHJlZSBpbiBwaHlsbwojIC0gYSBkYXRhZnJhbWUgd2l0aCB0aGUgaGVhZGVycyBjKCJTYW1wbGVfTmFtZSIsIlNhbXBsZV9ZZWFyIikKCnBsb3RSb290VG9UaXAgPC0gZnVuY3Rpb24oaW5wdXQubWwudHJlZSwgaW5wdXQuZGF0ZXMuZGYpewogIHRyZWUuZGF0YSA8LSBkYXRhLmZyYW1lKGdndHJlZTo6Zm9ydGlmeShpbnB1dC5tbC50cmVlKSxzdHJpbmdzQXNGYWN0b3JzID0gRikKICB0cmVlLmRhdGEkU2FtcGxlX05hbWUgPC0gdHJlZS5kYXRhJGxhYmVsCiAgdHJlZS5kYXRhIDwtIHBseXI6OmpvaW4odHJlZS5kYXRhLCBpbnB1dC5kYXRlcy5kZiwgYnk9IlNhbXBsZV9OYW1lIiwgdHlwZT0ibGVmdCIpCiAgUm9vdFRvdGlwRGlzdGFuY2VzIDwtIHRyZWUuZGF0YVt0cmVlLmRhdGEkaXNUaXA9PVRSVUUsIngiXQogIHRyZWVMYWJlbHMgPC0gdHJlZS5kYXRhW3RyZWUuZGF0YSRpc1RpcD09VFJVRSwiU2FtcGxlX05hbWUiXQogIG50aXBzIDwtIGxlbmd0aCh0cmVlTGFiZWxzKQogIHRyZWVEYXRlcyA8LSBhcy5udW1lcmljKHRyZWUuZGF0YVt0cmVlLmRhdGEkaXNUaXA9PVRSVUUsIlNhbXBsZV9ZZWFyIl0pCiAgbWF4ZGF0ZSA8LSBtYXgodHJlZURhdGVzKQogIG1pbmRhdGUgPC0gbWluKHRyZWVEYXRlcykKICB0cmVlTW9kZWwgPC0gbG0oUm9vdFRvdGlwRGlzdGFuY2VzIH4gdHJlZURhdGVzKQogIHRyZWVDb3JyZWxhdGlvbiA8LSBjb3IudGVzdCh0cmVlRGF0ZXMsIFJvb3RUb3RpcERpc3RhbmNlcywgbWV0aG9kID0gInBlYXJzb24iLCBjb25mLmxldmVsID0gMC45NSkKICBtb2RlbFN1bW1hcnkgPC0gc3VtbWFyeSh0cmVlTW9kZWwpCiAgeEludGVyY2VwdCA8LSAtY29lZih0cmVlTW9kZWwpWzFdL2NvZWYodHJlZU1vZGVsKVsyXQogIFJvb3RUb3RpcERGIDwtIGRhdGEuZnJhbWUoUm9vdFRvdGlwRGlzdGFuY2VzLHRyZWVEYXRlcykKICAKICBwbG90LnRyZWUuZGF0YS5yb290MnRpcCA8LSBnZ3Bsb3QoZGF0YSA9IFJvb3RUb3RpcERGLCBhZXModHJlZURhdGVzLCAgUm9vdFRvdGlwRGlzdGFuY2VzKSkgKwogICAgZ2VvbV9wb2ludChhbHBoYT0wLjI1LHNpemU9MiwgY29sb3VyID0gInJlZCIpICsKICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICBsYWJzKHg9IlllYXIiLHk9IlJvb3QgdG8gdGlwIGRpc3RhbmNlIikgKwogICAgI2dlb21fc21vb3RoKG1ldGhvZD0nbG0nLGZ1bGxyYW5nZT1ULHNlPVQpICsKICAgIHN0YXRfc21vb3RoKG1ldGhvZD0nbG0nLGZ1bGxyYW5nZT1ULHNlPVQpICsgIAogICAgZ2d0aXRsZShwYXN0ZTAoIlNsb3BlOiAiLGZvcm1hdEMobW9kZWxTdW1tYXJ5JGNvZWZmaWNpZW50c1syXSwgZm9ybWF0ID0gImUiLCBkaWdpdHMgPSAzKSwiOyAiLAogICAgICAgICAgICAgICAgICAiVE1SQ0E6ICIscm91bmQoeEludGVyY2VwdCwxKSwKICAgICAgICAgICAgICAgICAgIlxuIiwgIkNvcnJlbGF0aW9uIENvZWZmaWNpZW50OiAiLHJvdW5kKHRyZWVDb3JyZWxhdGlvbiRlc3RpbWF0ZSwzKSwKICAgICAgICAgICAgICAgICAgIjsgIiwgIlJeMjogIiwgZm9ybWF0KG1vZGVsU3VtbWFyeSRyLnNxdWFyZWQsZGlnaXRzPTMpLCJcbiIsbnRpcHMsIiB0aXBzIiwiOyBUaW1lc3BhbjogIixtaW5kYXRlLCItIixtYXhkYXRlKSkgKwogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSkpCiAgCiAgcmV0dXJuKHBsb3QudHJlZS5kYXRhLnJvb3QydGlwKQp9CgpgYGAKCgpub3cgcGxvdApgYGB7cn0KcC5zdWJzYW1wbGVkLk1MLnRpcHMuNnBDb3VudHJ5LnBTdWJsaW4ucm9vdDJ0aXAgPC0gcGxvdFJvb3RUb1RpcChzdWJzYW1wbGVkLk1MLnRpcHMuNnBDb3VudHJ5LnBTdWJsaW4udHJlZSwgVFBBLm1ldGExLjIucGluZWNvbmUuaGF2ZWRhdGVzWyxjKCJTYW1wbGVfTmFtZSIsIlNhbXBsZV9ZZWFyIildKQoKcC5zdWJzYW1wbGVkLk1MLnRpcHMuNnBDb3VudHJ5LnBTdWJsaW4ucm9vdDJ0aXAuMnZlcnNpb25zIDwtIHBsb3RfZ3JpZChwLnN1YnNhbXBsZWQuTUwudGlwcy42cENvdW50cnkucFN1Ymxpbi5yb290MnRpcCwgcC5zdWJzYW1wbGVkLk1MLnRpcHMuNnBDb3VudHJ5LnBTdWJsaW4ucm9vdDJ0aXAgKyBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygxNDAwLDIwMjApKSArIGNvb3JkX2NhcnRlc2lhbih4bGltPWMoMTQwMCwyMDIwKSwgeWxpbT1jKDAsOC41ZS01KSksIG5jb2w9MiwgbGFiZWxzPWMoJ0InLCdDJyksIGxhYmVsX3NpemU9MTEpIAoKcC5zdWJzYW1wbGVkLk1MLnRpcHMuNnBDb3VudHJ5LnBTdWJsaW4ucm9vdDJ0aXAuMnZlcnNpb25zIApgYGAKClBsb3QgTUwgU3VidHJlZSB3aXRoIHJvb3QtMi10aXAgZ3JhcGgKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTgsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgojQ2Fpcm86OkNhaXJvKGZpbGU9cGFzdGUwKEZpZ3VyZV9vdXRwdXRfZGlyZWN0b3J5LCAiU3VwcGxlbWVudGFyeV9GaWd1cmUxNV9fTUwtc3VidHJlZTEtd2l0aC1yb290MnRpcF8wMi0yMDIxLnN2ZyIpLCB3aWR0aCA9IDgwMCwgaGVpZ2h0ID0gODAwLHR5cGU9InN2ZyIsdW5pdHMgPSAicHQiKQpwbG90X2dyaWQocGxvdC5zdWJzYW1wbGVkLk1MLnRpcHMuNnBDb3VudHJ5LnBTdWJsaW4udHJlZSAreWxpbSgtMSwxMzkpLCBwLnN1YnNhbXBsZWQuTUwudGlwcy42cENvdW50cnkucFN1Ymxpbi5yb290MnRpcC4ydmVyc2lvbnMsIG5jb2w9MSwgc2NhbGU9MC45LCBsYWJlbHM9YygnQScsJycpLCBsYWJlbF9zaXplPTExKQojZGV2Lm9mZigpCmBgYAoKCgpUb29rIHNlcXVlbmNlIGFsaWdubWVudCBmcm9tIHRoaXMgdHJlZSwgYW5kIGFuYWx5c2VkIHVzaW5nIEJFQVNUIDEuOC40CgoKQkVBU1QgYW5hbHlzaXMgKEhZSyBzdWJzdCBtb2RlbCksIGNvbXBhcmluZyAKClN0cmljdCAtIENvbnN0YW50IHBvcApTdHJpY3QgLSBTa3lsaW5lIHBvcCAoMTAgY2F0cykKUmVsTG9nTm9ybWFsIC0gQ29uc3RhbnQgcG9wClJlbExvZ05vcm1hbCAtIEV4cG9uZW50aWFsIHBvcApSZWxMb2dOb3JtYWwgLSBTa3lsaW5lIHBvcCAoMTAgY2F0cykKCi0gQ2FuJ3QgcmVqZWN0IHN0cmljdCBjbG9jayAodWNsZGV2LnNkIG92ZXJsYXBzIHplcm8gc3VidGFudGlhbGx5KQotIFN0ZXBwaW5nIHN0b25lIGFuYWx5c2lzIHNob3dzIFN0cmljay1Ta3lsaW5lIGlzIGJlc3QgbW9kZWwgKGFsdGhvdWdoIFN0cmljdCBDb25zdGFudCBpcyBuZWFybHkgYXMgY2xvc2UpCgpCcmluZyBpbiBTdHJpY3QgU2t5bGluZSBCRUFTVCB0cmVlIGFuZCBwbG90CgoKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBCcmluZyBpbiBiZWFzdCB0cmVlIGFuZCBleHRyYWN0IHRyZWUgZGF0YSBpbnRvIGRhdGFmcmFtZQpUUEEuYmVhc3QudHJlZSA8LSByZWFkLmJlYXN0KFRQQS5iZWFzdC5zdWJ0cmVlLmZpbGUpClRQQS5iZWFzdC50cmVlLmRhdGEgPC0gZGF0YS5mcmFtZShmb3J0aWZ5KFRQQS5iZWFzdC50cmVlKSxzdHJpbmdzQXNGYWN0b3JzID0gRikKCgojIEJFQVNUIHRpcG5hbWVzIGhhdmUgZGF0ZSBpbmNsdWRlZCAtIGxldHMgcmVtb3ZlIHRoYXQgZm9yIHBsb3R0aW5nIHdpdGggbWV0YWRhdGEKVFBBLmJlYXN0LnRpcG5hbWVzIDwtIGRhdGEuZnJhbWUoYmVhc3QubmFtZT1UUEEuYmVhc3QudHJlZUBwaHlsbyR0aXAubGFiZWwsc3RyaW5nc0FzRmFjdG9ycyA9IEYpClRQQS5iZWFzdC50aXBuYW1lcyRtZXRhLm5hbWUgPC0gZ3N1YigiXFx8LiskIiwiIiwgVFBBLmJlYXN0LnRpcG5hbWVzJGJlYXN0Lm5hbWUpClRQQS5iZWFzdC50cmVlQHBoeWxvJHRpcC5sYWJlbCA8LSBUUEEuYmVhc3QudGlwbmFtZXMkbWV0YS5uYW1lCiNUUEEuYmVhc3QudHJlZUBwaHlsbyR0aXAubGFiZWwKCgojIEJ1aWxkIHBsb3QKVFBBLmJlYXN0LnBsb3QxIDwtIGdndHJlZShUUEEuYmVhc3QudHJlZSxtcnNkPSIyMDE5LTA2LTAxIixsYWRkZXJpemUgPSBUKSArIAogIHRoZW1lX3RyZWUyKCkgKwogICMgQWRkIGRhdGUgbGluZXMgZm9yIGVhc3kgaW50ZXJwcmV0YXRpb24gIAogIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YygxMzAwLDE0MDAsMTUwMCwxNjAwLDE3MDAsMTgwMCwxODUwLDE5MDAsMTkyNSwxOTUwLDE5NzUsMjAwMCwyMDIwKSwgbWlub3JfYnJlYWtzPXNlcSgxOTUwLCAyMDIwLCA1KSkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgICA9IGVsZW1lbnRfbGluZShjb2xvcj0iZ3JleTUwIiwgc2l6ZT0uMiksCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciAgID0gZWxlbWVudF9saW5lKGNvbG9yPSJncmV5ODUiLCBzaXplPS4yKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpKSAKIyBBZGQgcG9zdGVyaW9yIHN1cHBvcnQgYXMgbm9kZSBwb2ludHMKVFBBLmJlYXN0LnBsb3QxIDwtIFRQQS5iZWFzdC5wbG90MSArIGdlb21fcG9pbnQyKGFlcyhzdWJzZXQ9KCFpc1RpcCAmIGFzLm51bWVyaWMocG9zdGVyaW9yKT4wLjgpKSxjb2xvcj0iZ3JheTYwIixzaXplPTIuNSxhbHBoYT0wLjUsIHNoYXBlPTE4KSArIAogIGdlb21fcG9pbnQyKGFlcyhzdWJzZXQ9KCFpc1RpcCAmIGFzLm51bWVyaWMocG9zdGVyaW9yKT4wLjkxKSksY29sb3I9ImdyYXk0MCIsc2l6ZT0yLjUsc2hhcGU9MTgsYWxwaGE9MC41KSArIAogIGdlb21fcG9pbnQyKGFlcyhzdWJzZXQ9KCFpc1RpcCAmIGFzLm51bWVyaWMocG9zdGVyaW9yKT49MC45NikpLGNvbG9yPSJibGFjayIsc2l6ZT0yLjUsc2hhcGU9MTgsYWxwaGE9MC41KQoKCiMgUGxvdCA5NSUgSFBEIGludGVydmFscyAtIGdlb21fcmFuZ2Ugc2VlbXMgdW5hYmxlIHRvIGRvIGNvcnJlY3RseSB3aXRoIHRoaXMgdHJlZSAoa25vd24gYnVnIGZvciB0aXAgZGF0ZWQgdHJlZXMpLCBzbyBleHRyYWN0IGRhdGEgYW5kIHBsb3QgdXNpbmcgZ2VvbV9zZWdtZW50Cm1pbm1heCA8LSB0KG1hdHJpeCh1bmxpc3QoVFBBLmJlYXN0LnRyZWUuZGF0YVshaXMubmEoVFBBLmJlYXN0LnRyZWUuZGF0YSRoZWlnaHRfMC45NV9IUEQpLCJoZWlnaHRfMC45NV9IUEQiXSksbnJvdz0yKSkKYmFyX2RmIDwtIGRhdGEuZnJhbWUobm9kZV9pZD1UUEEuYmVhc3QudHJlZS5kYXRhWyFpcy5uYShUUEEuYmVhc3QudHJlZS5kYXRhJGhlaWdodF8wLjk1X0hQRCksIm5vZGUiXSxhcy5kYXRhLmZyYW1lKG1pbm1heCkpCm5hbWVzKGJhcl9kZikgPC0gYygnbm9kZV9pZCcsJ21pbicsJ21heCcpIApiYXJfZGYgPC0gYmFyX2RmICU+JSBmaWx0ZXIobm9kZV9pZCA+IE50aXAoVFBBLmJlYXN0LnRyZWVAcGh5bG8pKQpiYXJfZGYgPC0gYmFyX2RmICU+JSBsZWZ0X2pvaW4oVFBBLmJlYXN0LnBsb3QxJGRhdGEsIGJ5PWMoJ25vZGVfaWQnPSdub2RlJykpICU+JSBzZWxlY3Qobm9kZV9pZCxtaW4sbWF4LHkpCm1yY2QuZGVjaW1hbCA8LSBkZWNpbWFsX2RhdGUoYXMuRGF0ZSgiMjAxOS0wNi0wMSIsIiVZLSVtLSVkIikpClRQQS5iZWFzdC5wbG90MSA8LSBUUEEuYmVhc3QucGxvdDEgKyBnZW9tX3NlZ21lbnQoYWVzKHg9bXJjZC5kZWNpbWFsLW1heCwgeT15LCB4ZW5kPW1yY2QuZGVjaW1hbC1taW4sIHllbmQ9eSksIGRhdGE9YmFyX2RmLCBjb2xvcj0ncmVkJywgYWxwaGE9MC4yLCBzaXplPTIuMjUpCgpUUEEuYmVhc3QucGxvdDEgPC0gVFBBLmJlYXN0LnBsb3QxICsgbmV3X3NjYWxlX2ZpbGwoKQoKVFBBLmJlYXN0LnBsb3QxICsgZ2VvbV90aXBsYWIoc2l6ZT0yLCBhbGlnbj1UKQpgYGAKCgp3aXRoIG1ldGFkYXRhCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpUUEEuYmVhc3QucGxvdDEubWV0YSA8LSBnaGVhdG1hcChUUEEuYmVhc3QucGxvdDEsCiAgICAgICAgICAgICAgIGRhdGEuZnJhbWUocm93Lm5hbWVzPVRQQS5tZXRhMS4yLnBpbmVjb25lJFNhbXBsZV9OYW1lLCBTdWJsaW5lYWdlPVRQQS5tZXRhMS4yLnBpbmVjb25lJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlKSwgY29sb3I9TlVMTCx3aWR0aD0wLjA1LCBvZmZzZXQ9Mixjb2xuYW1lc19hbmdsZT0wLGNvbG5hbWVzX29mZnNldF95PS0xLCBmb250LnNpemU9Mi41KSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWU9IlN1YmxpbmVhZ2UiLHZhbHVlcz1zdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZS5jb2xzLCBicmVha3M9c3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2UpICsKICB0aGVtZS50ZXh0LnNpemUKVFBBLmJlYXN0LnBsb3QxLm1ldGEgPC0gVFBBLmJlYXN0LnBsb3QxLm1ldGEgKyBuZXdfc2NhbGVfZmlsbCgpCgoKVFBBLmJlYXN0LnBsb3QxLm1ldGEgPC0gZ2hlYXRtYXAoVFBBLmJlYXN0LnBsb3QxLm1ldGEsVFBBLnJhd3NlcS5jb3VudHJpZXMucCwgY29sb3I9TlVMTCx3aWR0aD0wLjA1LG9mZnNldD0zNiwgY29sbmFtZXNfYW5nbGU9MCxjb2xuYW1lc19vZmZzZXRfeT0tMSwgZm9udC5zaXplPTIuNSkgKyAKICBzY2FsZV9maWxsX21hbnVhbChuYW1lPSJDb3VudHJ5Iix2YWx1ZXM9Y29udGluZW50YWwuY291bnRyeS5jb2xzLmJyZXcyJGNvdW50cnkuY29sLCBicmVha3M9Y29udGluZW50YWwuY291bnRyeS5jb2xzLmJyZXcyJEdlb19Db3VudHJ5KSArCiAgdGhlbWUudGV4dC5zaXplClRQQS5iZWFzdC5wbG90MS5tZXRhIDwtIFRQQS5iZWFzdC5wbG90MS5tZXRhICsgbmV3X3NjYWxlX2ZpbGwoKQpiZWFzdC5jb3VudHJ5LmxlZ2VuZCA8LSBnZXRfbGVnZW5kKFRQQS5iZWFzdC5wbG90MS5tZXRhICsgdGhlbWUobGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjY1LCJsaW5lIiksbGVnZW5kLnBvc2l0aW9uPSdyaWdodCcpKQoKVFBBLmJlYXN0LnBsb3QxLm1ldGEgPC0gZ2hlYXRtYXAoVFBBLmJlYXN0LnBsb3QxLm1ldGEsZGF0YS5mcmFtZShyb3cubmFtZXM9VFBBLm1ldGExLjIucGluZWNvbmUkU2FtcGxlX05hbWUsIFllYXI9VFBBLm1ldGExLjIucGluZWNvbmUkU2FtcGxlXzV5ZWFyLndpbmRvdywgc3RyaW5nc0FzRmFjdG9ycyA9IEYpLCBjb2xvcj1OVUxMLHdpZHRoPTAuMDUsIG9mZnNldD03MCxjb2xuYW1lc19hbmdsZT0wLGNvbG5hbWVzX29mZnNldF95PS0xLCBmb250LnNpemU9Mi41KSArIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWU9IlllYXIiLHZhbHVlcz1UUEEuNXllYXIud2luZG93LmJyZXdjb2xzJHdpbmRvdy41eWVhci5jb2xzWzE6KGxlbmd0aChUUEEuNXllYXIud2luZG93LmJyZXdjb2xzJHdpbmRvdy41eWVhci5jb2xzKS0xKV0sIGJyZWFrcz1UUEEuNXllYXIud2luZG93LmJyZXdjb2xzJHdpbmRvdy41eWVhclsxOihsZW5ndGgoVFBBLjV5ZWFyLndpbmRvdy5icmV3Y29scyR3aW5kb3cuNXllYXIpLTEpXSkgKwogIHRoZW1lLnRleHQuc2l6ZSArIAogICN0aGVtZShsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNjUsImxpbmUiKSxsZWdlbmQucG9zaXRpb249J2xlZnQnKSAjKwogICNndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQobmNvbD0zKSkgKwogIE5VTEwKVFBBLmJlYXN0LnBsb3QxLm1ldGEgPC0gVFBBLmJlYXN0LnBsb3QxLm1ldGEgKyBuZXdfc2NhbGVfZmlsbCgpCmJlYXN0LnllYXIubGVnZW5kIDwtIGdldF9sZWdlbmQoVFBBLmJlYXN0LnBsb3QxLm1ldGEgKyB0aGVtZShsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNjUsImxpbmUiKSxsZWdlbmQucG9zaXRpb249J3JpZ2h0JykpCgoKVFBBLmJlYXN0LnBsb3QxLm1ldGEgPC0gVFBBLmJlYXN0LnBsb3QxLm1ldGEgKyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAyMDAwLCBjb2xvcj0nYmx1ZScsIGFscGhhPTAuNSkKVFBBLmJlYXN0LnBsb3QxLm1ldGEgPC0gVFBBLmJlYXN0LnBsb3QxLm1ldGEgKyBhbm5vdGF0ZSgicmVjdCIseG1pbj0yMDAwLHhtYXg9MjAyMCx5bWluPS0xLHltYXg9MTM4LGFscGhhPTAuMSwgZmlsbD0nYmx1ZScpCmBgYAoKTG9vayBhdCBhbmQgcGxvdCBza3lsaW5lIGRhdGEKYGBge3J9CmJlYXN0LnN1YnRyZWUuc2t5bGluZSA8LSByZWFkLnRhYmxlKGJlYXN0LnN1YnRyZWUuc2t5bGluZS5maWxlLCBzZXA9Ilx0IiwgY2hlY2submFtZXM9RiwgY29tbWVudC5jaGFyPSIiLCBoZWFkZXI9VCwgc3RyaW5nc0FzRmFjdG9ycz1GKQoKcC5iZWFzdC5zdWJ0cmVlLnNreWxpbmUgPC0gZ2dwbG90KGJlYXN0LnN1YnRyZWUuc2t5bGluZSwgYWVzKFRpbWUsTWVkaWFuKSkgKyAKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9yaWJib24oYWVzKHltaW49TG93ZXIsIHltYXg9VXBwZXIpLCBhbHBoYT0wLjIsIGZpbGw9J2JsYWNrJykgKwogIHRoZW1lX2xpZ2h0KCkgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoc2VxKDE3NDAsMjAyMCwyMCkpLCBleHBhbmQ9YygwLjAxLDAuMDEpKSArCiAgc2NhbGVfeV9sb2cxMCgpICsgCiAgY29vcmRfY2FydGVzaWFuKHg9YygxNzUwLDIwMjApLCB5PWMoNTAsMzAwMCkpICsgCiAgdGhlbWUudGV4dC5zaXplICsKICAjbGFicyh5PSJNZWRpYW4gZWZmZWN0aXZlIHBvcHVsYXRpb24gc2l6ZSIsIHg9IlllYXIiKSArIAogIGxhYnMoeT0iUmVsYXRpdmUgZ2VuZXRpYyBkaXZlcnNpdHkiLCB4PSJZZWFyIikgKyAKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAyMDAwLCBjb2xvcj0nYmx1ZScsIGFscGhhPTAuNSkgKwogIGFubm90YXRlKCJyZWN0Iix4bWluPTIwMDAseG1heD0yMDIwLHltaW49MCx5bWF4PTEwMDAwLGFscGhhPTAuMSwgZmlsbD0nYmx1ZScpCiNwLmJlYXN0LnN1YnRyZWUuc2t5bGluZQpgYGAKCkxvb2sgYXQgbGluZWFnZSBwcmVkaXRpb25zCmBgYHtyfQpiZWFzdC5zdWJ0cmVlLnNreWxpbmUubGluZWFnZXMgPC0gcmVhZC50YWJsZShiZWFzdC5zdWJ0cmVlLnNreWxpbmUubGluZWFnZS5maWxlLCBzZXA9Ilx0IiwgY2hlY2submFtZXM9RiwgY29tbWVudC5jaGFyPSIiLCBoZWFkZXI9VCwgc3RyaW5nc0FzRmFjdG9ycz1GKQoKcC5iZWFzdC5zdWJ0cmVlLnNreWxpbmUubGluZWFnZXMgPC0gZ2dwbG90KGJlYXN0LnN1YnRyZWUuc2t5bGluZS5saW5lYWdlcywgYWVzKFRpbWUsTWVkaWFuKSkgKyAKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9yaWJib24oYWVzKHltaW49TG93ZXIsIHltYXg9VXBwZXIpLCBhbHBoYT0wLjIsIGZpbGw9J2JsYWNrJykgKwogIHRoZW1lX2xpZ2h0KCkgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoc2VxKDE3NDAsMjAyMCwyMCkpLCBleHBhbmQ9YygwLjAxLDAuMDEpKSArCiAgc2NhbGVfeV9sb2cxMCgpICsgCiAgY29vcmRfY2FydGVzaWFuKHg9YygxNzUwLDIwMjApLCB5PWMoMSwzMDApKSArIAogIHRoZW1lLnRleHQuc2l6ZSArCiAgbGFicyh5PSJMaW5lYWdlcyIsIHg9IlllYXIiKSArIAogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDIwMDAsIGNvbG9yPSdibHVlJywgYWxwaGE9MC41KSArCiAgYW5ub3RhdGUoInJlY3QiLHhtaW49MjAwMCx4bWF4PTIwMjAseW1pbj0wLHltYXg9NTAwLGFscGhhPTAuMSwgZmlsbD0nYmx1ZScpCiNwLmJlYXN0LnN1YnRyZWUuc2t5bGluZS5saW5lYWdlcwpgYGAKCgpNYWtlIGNvbWJpbmVkIHBsb3QKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0Kc2t5bGluZS5yb3cgPC0gcGxvdF9ncmlkKE5VTEwscC5iZWFzdC5zdWJ0cmVlLnNreWxpbmUsTlVMTCwgbmNvbD0zLCByZWxfd2lkdGhzID0gYygxLDMsMSkpCmxpbmVhZ2Uucm93IDwtIHBsb3RfZ3JpZChOVUxMLHAuYmVhc3Quc3VidHJlZS5za3lsaW5lLmxpbmVhZ2VzLE5VTEwsIG5jb2w9MywgcmVsX3dpZHRocyA9IGMoMSwzLDEpKQoKI2JvdGguc2t5bGluZS5saW5lYWdlLnJvd3MgPC0gcGxvdF9ncmlkKHNreWxpbmUucm93LCBsaW5lYWdlLnJvdywgYWxpZ249VCwgbmNvbD0xLCBsYWJlbHM9YygnQicsJ0MnKSkKYm90aC5za3lsaW5lLmxpbmVhZ2Uucm93cyA8LSBwbG90X2dyaWQoc2t5bGluZS5yb3csIGFsaWduPVQsIG5jb2w9MSwgbGFiZWxzPWMoJ0InKSxsYWJlbF9zaXplPTExKQoKCiNwbG90LmJlYXN0LndpdGguc2t5bGluZSA8LSBwbG90X2dyaWQoVFBBLmJlYXN0LnBsb3QxLm1ldGEgKyB0aGVtZShsZWdlbmQucG9zaXRpb249J25vbmUnKSArIHlsaW0oLTEsMTM4KSwgYm90aC5za3lsaW5lLmxpbmVhZ2Uucm93cywgbmNvbD0xLCBhbGlnbj1ULCByZWxfaGVpZ2h0cyA9IGMoMiwyKSxsYWJlbHM9YygnQScsJycpLCBsYWJlbF9zaXplPTExKQoKcGxvdC5iZWFzdC53aXRoLnNreWxpbmUgPC0gcGxvdF9ncmlkKFRQQS5iZWFzdC5wbG90MS5tZXRhICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSdub25lJykgKyB5bGltKC0xLDEzOCksIGJvdGguc2t5bGluZS5saW5lYWdlLnJvd3MsIG5jb2w9MSwgYWxpZ249VCwgcmVsX2hlaWdodHMgPSBjKDMsMSksbGFiZWxzPWMoJ0EnLCcnKSwgbGFiZWxfc2l6ZT0xMSkKCmJlYXN0LmxlZ2VuZC5jb21iaW5lZCA8LSBwbG90X2dyaWQoYmVhc3QueWVhci5sZWdlbmQsIE5VTEwsIG5jb2w9MSwgcmVsX2hlaWdodHM9YygzLDEpKQoKCgojQ2Fpcm86OkNhaXJvKGZpbGU9cGFzdGUwKEZpZ3VyZV9vdXRwdXRfZGlyZWN0b3J5LCAiU3VwcGxlbWVudGFyeV9GaWd1cmUxNl9zdWJzYW1wbGUxMzhfQkVBU1QtU3RyaWN0Q1NreWxpbmVfMDItMjAyMS5zdmciKSwgd2lkdGggPSA4MDAsIGhlaWdodCA9IDgwMCx0eXBlPSJzdmciLHVuaXRzID0gInB0IikKcGxvdF9ncmlkKGJlYXN0LmxlZ2VuZC5jb21iaW5lZCwgcGxvdC5iZWFzdC53aXRoLnNreWxpbmUsIG5jb2w9MiwgcmVsX3dpZHRocz1jKDEsMTApLCBsYWJlbHM9YygnS2V5JywnJyksIGxhYmVsX3NpemU9MTEpCiNkZXYub2ZmKCkKYGBgCgoKCgpQdWxsIG91dCBNUkNBIG5vZGVzIGFuZCBkYXRlIHJhbmdlcyBmcm9tIGJlYXN0IHN1YnRyZWUgYW5kIHN1YmxpbmVhZ2VzCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgU3Vic2V0IG1ldGFkYXRhClRQQS5tZXRhMS4yLmJlYXN0LnN1YnNldDEgPC0gVFBBLm1ldGExLjIucGluZWNvbmVbVFBBLm1ldGExLjIucGluZWNvbmUkU2FtcGxlX05hbWUgJWluJSBhcy5waHlsbyhUUEEuYmVhc3QudHJlZSkkdGlwLmxhYmVsLF0KIyBEZWZpbmUga2V5IHN1YmxpbmVhZ2VzCiNFeHBhbmRlZC5zdWJsaW5lYWdlcyA8LSBkYXRhLmZyYW1lKFN1YmxpbmVhZ2U9YygyLDMsNSw2LDEyLDE5KSwgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCkV4cGFuZGVkLnN1YmxpbmVhZ2VzIDwtIGRhdGEuZnJhbWUoU3VibGluZWFnZT1jKDEsMiw4LDE0KSwgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCgoKIyBSdW4gbG9vcCB0byBleHRyYWN0IE1SQ0Egbm9kZSBmb3IgZWFjaCBzdWJsaW5lYWdlCkV4cGFuZGVkLnN1YmxpbmVhZ2Uubm9kZXMgPC0gTlVMTApmb3IgKGN1cnJlbnQuc3VibGluZWFnZS5leHAxIGluIEV4cGFuZGVkLnN1YmxpbmVhZ2VzJFN1YmxpbmVhZ2UpIHsKICBFeHBhbmRlZC5zdWJsaW5lYWdlLm5vZGVzIDwtIGMoRXhwYW5kZWQuc3VibGluZWFnZS5ub2RlcywgYXBlOjpnZXRNUkNBKGFzLnBoeWxvKFRQQS5iZWFzdC50cmVlKSxhcy5jaGFyYWN0ZXIoVFBBLm1ldGExLjIuYmVhc3Quc3Vic2V0MVtUUEEubWV0YTEuMi5iZWFzdC5zdWJzZXQxJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlPT1jdXJyZW50LnN1YmxpbmVhZ2UuZXhwMSwiU2FtcGxlX05hbWUiXSkpKQp9CkV4cGFuZGVkLnN1YmxpbmVhZ2VzJG5vZGUgPC0gRXhwYW5kZWQuc3VibGluZWFnZS5ub2RlcwojRXhwYW5kZWQuc3VibGluZWFnZXMKCiMgU3BsaXQgc3VibGluZWFnZSAyIGluIHRoaXMgdHJlZSBjcmVhdGVzIGEgcHJvYmxlbS4gQ2hhbmdlIGl0IHRvIDE4MAojRXhwYW5kZWQuc3VibGluZWFnZXNbRXhwYW5kZWQuc3VibGluZWFnZXMkc3VibGluZWFnZT09MixdCkV4cGFuZGVkLnN1YmxpbmVhZ2VzW0V4cGFuZGVkLnN1YmxpbmVhZ2VzJFN1YmxpbmVhZ2U9PTIsIm5vZGUiXSA8LSAxODAKCgpUUEEuYmVhc3QucGxvdDEgKyBnZW9tX3RleHQyKGFlcyhzdWJzZXQ9IWlzVGlwLCBsYWJlbD1ub2RlKSwgaGp1c3Q9LS4zLCBzaXplPTIpICsKICBnZW9tX3BvaW50MihhZXMoc3Vic2V0PShub2RlICVpbiUgRXhwYW5kZWQuc3VibGluZWFnZXMkbm9kZSkpLGNvbG9yPSJyZWQiKSArCiAgZ2d0aXRsZSgiUmVkIG5vZGVzIGluZGljYXRlIE1SQ0EgZm9yIGVhY2ggc3VibGluZWFnZSIpCgpgYGAKCmBgYHtyfQojRXh0cmFjdCByZWxldmFudCBub2RlcyBkYXRhIGZyb20gYmVhc3QgdHJlZSBkYXRhCkV4cGFuZGVkLnN1YmxpbmVhZ2Uubm9kZXMuYmVhc3QgPC0gcGx5cjo6am9pbihFeHBhbmRlZC5zdWJsaW5lYWdlcyxUUEEuYmVhc3QudHJlZS5kYXRhWyxjKCJub2RlIiwiaGVpZ2h0IiwiaGVpZ2h0XzAuOTVfSFBEIiwiaGVpZ2h0X21lZGlhbiIsImhlaWdodF9yYW5nZSIpXSwgYnk9Im5vZGUiKQoKIyBEYXRhIGlzIGluIHRoZSBmb3JtIG9mICJoZWlnaHQiIGluZm9ybWF0aW9uIC0gbmVlZCB0byBjb252ZXJ0IHRvIHllYXJzIHJlbGF0aXZlIHRvIG1yY2QgKDIwMTkvMDYvMDEpCkV4cGFuZGVkLnN1YmxpbmVhZ2Uubm9kZXMuYmVhc3QkbXJjYS5tZWRpYW4gPC0gMjAxOS41IC0gRXhwYW5kZWQuc3VibGluZWFnZS5ub2Rlcy5iZWFzdCRoZWlnaHRfbWVkaWFuCkV4cGFuZGVkLnN1YmxpbmVhZ2Uubm9kZXMuYmVhc3QkeWVhciA8LSBhcy5udW1lcmljKHJvdW5kKDIwMTkuNSAtIEV4cGFuZGVkLnN1YmxpbmVhZ2Uubm9kZXMuYmVhc3QkaGVpZ2h0X21lZGlhbiwwKSkKCgpFeHBhbmRlZC5zdWJsaW5lYWdlLm5vZGVzLmJlYXN0JG1yY2EuOTVoaWdoIDwtIHJvdW5kKDIwMTkuNSAtIHNhcHBseSgxOm5yb3coRXhwYW5kZWQuc3VibGluZWFnZS5ub2Rlcy5iZWFzdCksZnVuY3Rpb24oeCkgYXMubnVtZXJpYyh1bmxpc3QoRXhwYW5kZWQuc3VibGluZWFnZS5ub2Rlcy5iZWFzdFt4LCJoZWlnaHRfMC45NV9IUEQiXSkpWzFdKSkKCkV4cGFuZGVkLnN1YmxpbmVhZ2Uubm9kZXMuYmVhc3QkbXJjYS45NWxvdyA8LSByb3VuZCgyMDE5LjUgLSBzYXBwbHkoMTpucm93KEV4cGFuZGVkLnN1YmxpbmVhZ2Uubm9kZXMuYmVhc3QpLGZ1bmN0aW9uKHgpIGFzLm51bWVyaWModW5saXN0KEV4cGFuZGVkLnN1YmxpbmVhZ2Uubm9kZXMuYmVhc3RbeCwiaGVpZ2h0XzAuOTVfSFBEIl0pKVsyXSkpCgoKRXhwYW5kZWQuc3VibGluZWFnZS5ub2Rlcy5iZWFzdCA8LSBFeHBhbmRlZC5zdWJsaW5lYWdlLm5vZGVzLmJlYXN0W29yZGVyKEV4cGFuZGVkLnN1YmxpbmVhZ2Uubm9kZXMuYmVhc3QkU3VibGluZWFnZSksXQpFeHBhbmRlZC5zdWJsaW5lYWdlLm5vZGVzLmJlYXN0JFN1YmxpbmVhZ2UgPC0gZmFjdG9yKEV4cGFuZGVkLnN1YmxpbmVhZ2Uubm9kZXMuYmVhc3QkU3VibGluZWFnZSwgbGV2ZWxzPXJldihzdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZSkpCkV4cGFuZGVkLnN1YmxpbmVhZ2Uubm9kZXMuYmVhc3Qkc3ViLm9yZGVyIDwtIHJldihjKDE6bnJvdyhFeHBhbmRlZC5zdWJsaW5lYWdlLm5vZGVzLmJlYXN0KSkpCgoKYGBgCgoKClJlcGVhdCBCRUFTVCBzdWJzYW1wbGluZywgYnV0IGVuc3VyZSBhbGwgeWVhciBhcmUgcmVwcmVzZW50ZWQgKGFuZCBtYWtlIGEgc2xpZ2h0bHkgYmlnZ2VyIHRyZWUpCgpgYGB7cn0KCnllYXIubGlzdCA8LSBzb3J0KHVuaXF1ZShUUEEubWV0YTEuMi5waW5lY29uZS5oYXZlZGF0ZXMkU2FtcGxlX1llYXIpKQoKCm15c2FtcGxlc2l6ZS4yIDwtIDMKdG90YWwuYm9vdHN0cmFwcy4yIDwtIDEKCmFsbC5ib290c3RyYXBzLmxpc3RzLjIgPC0gTlVMTAphbGwuYm9vdHN0cmFwcy50cmVlcy4yIDwtIGMocnRyZWUoMjApKSAjIGNyZWF0ZSB3aXRoIHJhbmRvbSBzdGFydCB0cmVlIHRvIGZvcmNlIGludG8gYSBtdWx0aXBoeWxvIG9iamVjdApjdXJyZW50LmJvb3RzdHJhcC4yIDwtIDAKcmVwZWF0IHsKICBjb3VudHJ5LnNhbXBsZS4yIDwtIE5VTEwKICBmb3IgKGN1cnJlbnQueWVhci4yIGluIHllYXIubGlzdCkgeyAKICAgIGZvciAoY3VycmVudC5saW5lYWdlLjIgaW4gc3VibGluZWFnZS5saW5lYWdlLmxpc3QyKXsKICAgICAgZm9yIChjdXJyZW50LmNvdW50cnkuMiBpbiBDb3VudHJ5Lmxpc3QyKXsKICAgICAgICBjdXJyZW50Lmxpc3QuMiA8LSBUUEEubWV0YTEuMi5waW5lY29uZS5oYXZlZGF0ZXNbKFRQQS5tZXRhMS4yLnBpbmVjb25lLmhhdmVkYXRlcyRUUEEucGluZWNvbmUuc3VibGluZWFnZT09Y3VycmVudC5saW5lYWdlLjIgJiBUUEEubWV0YTEuMi5waW5lY29uZS5oYXZlZGF0ZXMkR2VvX0NvdW50cnk9PWN1cnJlbnQuY291bnRyeS4yICYgVFBBLm1ldGExLjIucGluZWNvbmUuaGF2ZWRhdGVzJFNhbXBsZV9ZZWFyPT1jdXJyZW50LnllYXIuMiksIlNhbXBsZV9OYW1lIl0KICAgICAgICBjdXJyZW50Lmxpc3QuMiA8LSBjdXJyZW50Lmxpc3QuMlshaXMubmEoY3VycmVudC5saXN0LjIpXQogICAgICAgIGlmIChsZW5ndGgoY3VycmVudC5saXN0LjIpPjEpewogICAgICAgICAgY3VycmVudC5zYW1wbGUuMiA8LSB1bmlxdWUoc2FtcGxlKGN1cnJlbnQubGlzdC4yLHNpemU9bXlzYW1wbGVzaXplLjIsIHJlcGxhY2U9VCkpCiAgICAgICAgICBjb3VudHJ5LnNhbXBsZS4yIDwtIGMoYXMudmVjdG9yKGN1cnJlbnQuc2FtcGxlLjIpLCBjb3VudHJ5LnNhbXBsZS4yKQogICAgICAgIH0KICAgICAgfQogICAgfQogIH0KICBjb3VudHJ5LnNhbXBsZS4yIDwtIGMoY291bnRyeS5zYW1wbGUuMiwgYXMudmVjdG9yKFRQQS5tZXRhMS4yLnBpbmVjb25lLmhhdmVkYXRlc1soVFBBLm1ldGExLjIucGluZWNvbmUuaGF2ZWRhdGVzJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlPT0iU2luZ2xldG9uIiksIlNhbXBsZV9OYW1lIl0pKQogIAogIGN1cnJlbnQuYm9vdHN0cmFwLjIgPC0gY3VycmVudC5ib290c3RyYXAuMiArIDEKICBjdXJyZW50LnNhbXBsZS50cmVlLjIgPC0gKGFwZTo6a2VlcC50aXAoVFBBLk1MdHJlZSwgY291bnRyeS5zYW1wbGUuMikpCiAgYWxsLmJvb3RzdHJhcHMudHJlZXMuMiA8LSBjKGFsbC5ib290c3RyYXBzLnRyZWVzLjIsYyhjdXJyZW50LnNhbXBsZS50cmVlLjIpLHJlY3Vyc2l2ZT1UKQogIGFsbC5ib290c3RyYXBzLmxpc3RzLjIgPC0gYyhhbGwuYm9vdHN0cmFwcy5saXN0cy4yLCBsaXN0KGNvdW50cnkuc2FtcGxlLjIpKQogIGlmIChjdXJyZW50LmJvb3RzdHJhcC4yID09IHRvdGFsLmJvb3RzdHJhcHMuMil7CiAgICBicmVhawogIH0KfQphbGwuYm9vdHN0cmFwcy50cmVlcy4yIDwtIGFsbC5ib290c3RyYXBzLnRyZWVzLjJbYygyOih0b3RhbC5ib290c3RyYXBzLjIrMSkpXSAjIHJlbW92ZSByYW5kb20gc3RhcnQgdHJlZQoKI2FsbC5ib290c3RyYXBzLnRyZWVzW1sxXV0KI3N1YnNhbXBsZWQuTUwudGlwcy4zcHYuY291bnRyeS5kYXRlcy5zdWJsaW4gPC0gYWxsLmJvb3RzdHJhcHMudHJlZXMuMltbMV1dJHRpcC5sYWJlbAoKIyBPdXRwdXRzIGZyb20gYSBwcmV2aW91cyByYW5kb20gbG9vcCB1c2VkIGJlbG93IHRvIGVuc3VyZSBzYW1wbGUgcmVtYWlucyB0aGUgc2FtZQpzdWJzYW1wbGVkLk1MLnRpcHMuM3B2LmNvdW50cnkuZGF0ZXMuc3VibGluIDwtIGMoIk1leGljb19BLW1jZiIsICJUUEFfUlVTX1R1dmEtNjIiLCAiVFBBX1JVU19UdXZhLTM5IiwgIlRQQV9SVVNfVHV2YS02MSIsICJQSEUxNDAwNzNBIiwgIlVXMzM3QiIsICJVVzE4NkIiLCAiVVczMzBCIiwgIlVXMjEzQiIsICJVVzIxNUIiLCAiUEhFMTUwMTI5QSIsICJUUEFfVUtCUkcwMTciLCAiVFBBX0JDQzE2MSIsICJUUEFfT01JMDA2IiwgIlVXMjMxQiIsICJVVzE4N0IiLCAiSzMiLCAiU0hFX1YiLCAiU0hHX0kyIiwgIkMzIiwgIlRQQV9CQ0MxNjUiLCAiVFBBX1VTTC1CQUwtMiIsICJTUzE0X3YyIiwgIlRQQV9IVU4yMDAwMjQiLCAiVFBBX0hVTjE5MDAyMiIsICJUUEFfVVNMLVNFQS04MS04IiwgIlRQQV9aSU0wMjUiLCAiVFBBX1pJTTAxOSIsICJUUEFfWklNMDA3IiwgIlVXMjYyQiIsICJVVzM5MUIiLCAiUEhFMTUwMTUxQSIsICJUUEFfVUtCSVIwMjYiLCAiVFBBX09NSTAwMiIsICJUUEFfQkNDMTM5IiwgIlRQQV9CQ0MxMzciLCAiVFBBX1VLQlJHMDE1IiwgIlBIRTEzMDA0MUEiLCAiUEhFMTMwMDUwQSIsICJVVzM3NkIiLCAiUEhFMTUwMTU5QSIsICJVVzI4MEIiLCAiVVcyNDRCIiwgIlRQQV9CQ0MxMjUiLCAiUEhFMTYwMjU0QSIsICJQVF9TSUYxMTgzIiwgIlBIRTE2MDI0OUEiLCAiUEhFMTcwMzc5QSIsICJQSEUxNjAzMTVBIiwgIlBIRTE2MDI2MEEiLCAiUEhFMTUwMTMxQSIsICJQSEUxNzA0MDJBIiwgIlBIRTE3MDM4MEEiLCAiVVc0NzNCIiwgIlVXNDkyQiIsICJUUEFfVVNMLVBoaWwtMSIsICJQSEUxMjAwMzBBIiwgIlBIRTEyMDAxNEEiLCAiUEhFMTMwMDQzQSIsICJQVF9TSUYxMTY3IiwgIlBIRTE0MDA5M0EiLCAiVFBBX0hVTjE5MDAyMyIsICJUUEFfQkNDMDU4IiwgIlRQQV9VU0wtU0VBLTg3LTEiLCAiVFBBX1VLQklSMDUwIiwgIlVXMTU1QiIsICJVVzIxMUIiLCAiVFBBX0JDQzAzOCIsICJUUEFfQkNDMDM0IiwgIlRQQV9CQ0MwMDgiLCAiVFBBX0JDQzAwOSIsICJVVzI1N0IiLCAiVVcxMzhCIiwgIlVXMTAyQiIsICJVVzM0NEIiLCAiVVcxMjZCIiwgIlNNVVRwXzAxIiwgIlNNVVRwXzA4IiwgIlVXMzgzQiIsICJUUEFfQUxDMTE1IiwgIlVXODIzQiIsICJQSEUxNzAzODVBIiwgIlVXMzA0QiIsICJQVF9TSUYwOTU0IiwgIlBUX1NJRjEyMDAiLCAiVFBBX0JDQzEyOCIsICJQSEUxMzAwNTZBIiwgIlRQQV9BTEMwMzYiLCAiVFBBX0JDQzAzMiIsICJUUEFfQkNDMTMyIiwgIlRQQV9BVVNCUi00NSIsICJUUEFfQkNDMTUzIiwgIlRQQV9BVVNCUi0zOSIsICJUUEFfSFVOMTgwMDA3IiwgIlVXNDExQiIsICJUUEFfRVNCQ04wMDIiLCAiUEhFMTQwMDc0QSIsICJUUEFfU1dFLTQ2NyIsICJQSEUxNTAxMjZBIiwgIlBIRTE3MDQxMkEiLCAiUEhFMTUwMTczQSIsICJUUEFfVUtCUkcwMDkiLCAiVFBBX0VTQkNOMDA0IiwgIlRQQV9CQ0MxMjMiLCAiVFBBX0JDQzE0NyIsICJUUEFfQkNDMDYzIiwgIlBIRTEyMDAyNEEiLCAiVFBBX0JDQzE3NCIsICJUUEFfU1dFLTU3NSIsICJUUEFfSFVOMTkwMDE3IiwgIlBIRTE2MDI0OEEiLCAiVFBBX0JDQzE3NiIsICJUUEFfSFVOMTgwMDAxIiwgIlBIRTEzMDA1NEEiLCAiVVc4NTJCIiwgIlBIRTE0MDA4MUEiLCAiVVcyNTlCIiwgIlRQQV9BVVNCUi0xMTMiLCAiUEhFMTYwMzAxQSIsICJUUEFfQkNDMTAyIiwgIlBUX1NJRjEyNzgiLCAiUFRfU0lGMDg3N18zIiwgIlBIRTE2MDI2NUEiLCAiQVUxNSIsICJUUEFfRUlSMDA4IiwgIlRQQV9BTEMwNTUiLCAiVFBBX0JDQzE3NSIsICJQVF9TSUYxMjgwIiwgIlRQQV9CQ0MxODUiLCAiVFBBX0JDQzExMSIsICJUUEFfQkNDMTU3IiwgIlRQQV9CQ0MwMzAiLCAiUEhFMTcwNDA5QSIsICJUUEFfQkNDMDQ5IiwgIlRQQV9CQ0MwNjEiLCAiVFBBX0JDQzA1MiIsICJQSEUxNTAxNjFBIiwgIlRQQV9BTEMxMjYiLCAiVFBBX09NSTAyMiIsICJVVzE4OUIiLCAiVVcyNzlCIiwgIlRQQV9PTUkwMjEiLCAiUEhFMTcwNDAxQSIsICJDVzU5IiwgIkNXODIiLCAiQkFMNzMiLCAiVFBBX1pJTTAxNSIsICJUUEFfWklNMDIwIiwgIlBIRTE1MDExOEEiLCAiUEhFMTcwMzMzQSIsICJQSEUxNjAzMDJBIiwgIlBIRTE0MDA4OUEiLCAiUEhFMTcwMzgxQSIsICJQSEUxNjAyNjNBIiwgIlRQQV9CQ0MwODkiLCAiUEhFMTYwMzE2QSIsICJUUEFfQkNDMTIyIiwgIlBIRTE3MDM4NkEiLCAiUEhFMTQwMDc2QSIsICJQSEUxNTAxNDlBIiwgIlRQQV9CQ0MxMzYiLCAiUEhFMTUwMTcwQSIsICJUUEFfVUtCUkcwMDciLCAiVFBBX0JDQzA4MSIsICJUUEFfQkNDMDEyIiwgIlBIRTEyMDAyOUEiLCAiUEhFMTIwMDMzQSIsICJUUEFfVVNMLUhhaXRpLUIiKQoKCgpzdWJzYW1wbGVkLk1MLnRpcHMuM3B2LmNvdW50cnkuZGF0ZXMuc3VibGluLnRyZWUgPC0gKGFwZTo6a2VlcC50aXAoVFBBLk1MdHJlZSwgc3Vic2FtcGxlZC5NTC50aXBzLjNwdi5jb3VudHJ5LmRhdGVzLnN1YmxpbikpCgpzdWJzYW1wbGVkLk1MLnRpcHMuM3B2LmNvdW50cnkuZGF0ZXMuc3VibGluLnRyZWUuZGF0YSA8LSBkYXRhLmZyYW1lKGZvcnRpZnkoc3Vic2FtcGxlZC5NTC50aXBzLjNwdi5jb3VudHJ5LmRhdGVzLnN1Ymxpbi50cmVlKSxzdHJpbmdzQXNGYWN0b3JzID0gRikKc3Vic2FtcGxlZC5NTC50aXBzLjNwdi5jb3VudHJ5LmRhdGVzLnN1Ymxpbi50cmVlLmRhdGEkU2FtcGxlX05hbWUgPC0gc3Vic2FtcGxlZC5NTC50aXBzLjNwdi5jb3VudHJ5LmRhdGVzLnN1Ymxpbi50cmVlLmRhdGEkbGFiZWwgCnN1YnNhbXBsZWQuTUwudGlwcy4zcHYuY291bnRyeS5kYXRlcy5zdWJsaW4udHJlZS5kYXRhIDwtIHBseXI6OmpvaW4oc3Vic2FtcGxlZC5NTC50aXBzLjNwdi5jb3VudHJ5LmRhdGVzLnN1Ymxpbi50cmVlLmRhdGEsIFRQQS5tZXRhMS4yLnBpbmVjb25lLmhhdmVkYXRlc1ssYygiU2FtcGxlX05hbWUiLCJUUEEucGluZWNvbmUubWFqb3IiLCJUUEEucGluZWNvbmUuc3VibGluZWFnZSIsICJTYW1wbGVfWWVhciIpXSwgYnk9IlNhbXBsZV9OYW1lIiwgdHlwZT0ibGVmdCIpCgpzdWJzYW1wbGVkLm1ldGFsaXN0MiA8LSBUUEEubWV0YTEuMi5waW5lY29uZVsoVFBBLm1ldGExLjIucGluZWNvbmUkU2FtcGxlX05hbWUgJWluJSBzdWJzYW1wbGVkLk1MLnRpcHMuM3B2LmNvdW50cnkuZGF0ZXMuc3VibGluKSxjKCJTYW1wbGVfTmFtZSIsIkNsZWFuZWRfZmFzdHFfaWQiLCJTYW1wbGVfWWVhciIpXSAKCgpwbG90LnN1YnNhbXBsZWQuTUwudGlwcy4zcHYuY291bnRyeS5kYXRlcy5zdWJsaW4udHJlZSA8LSBnZ3RyZWUoc3Vic2FtcGxlZC5NTC50aXBzLjNwdi5jb3VudHJ5LmRhdGVzLnN1Ymxpbi50cmVlKSAlPCslIGRhdGEuZnJhbWUoU2FtcGxlX05hbWU9VFBBLm1ldGExLjIucGluZWNvbmUkU2FtcGxlX05hbWUsIFN1YmxpbmVhZ2U9VFBBLm1ldGExLjIucGluZWNvbmUkVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UpICsgCiAgZ2VvbV90aXBwb2ludChhZXMoY29sb3I9U3VibGluZWFnZSksIHNpemU9MSwgYWxwaGE9MC41KSArIAogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lPSJTdWJsaW5lYWdlIix2YWx1ZXM9c3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2UuY29scywgYnJlYWtzPXN1YmxpbmVhZ2VzLmNvbHMuYnJldyRzdWJsaW5lYWdlKSAKCnBsb3Quc3Vic2FtcGxlZC5NTC50aXBzLjNwdi5jb3VudHJ5LmRhdGVzLnN1Ymxpbi50cmVlIDwtIGdoZWF0bWFwKHBsb3Quc3Vic2FtcGxlZC5NTC50aXBzLjNwdi5jb3VudHJ5LmRhdGVzLnN1Ymxpbi50cmVlLAogICAgICAgICAgICAgICBkYXRhLmZyYW1lKHJvdy5uYW1lcz1UUEEubWV0YTEuMi5waW5lY29uZSRTYW1wbGVfTmFtZSwgU3VibGluZWFnZT1UUEEubWV0YTEuMi5waW5lY29uZSRUUEEucGluZWNvbmUuc3VibGluZWFnZSksIGNvbG9yPU5VTEwsd2lkdGg9MC4wNCwgY29sbmFtZXNfYW5nbGU9MCxjb2xuYW1lc19vZmZzZXRfeT0tMSwgZm9udC5zaXplPTIuNSkgKyAKICBzY2FsZV9maWxsX21hbnVhbChuYW1lPSJTdWJsaW5lYWdlIix2YWx1ZXM9c3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2UuY29scywgYnJlYWtzPXN1YmxpbmVhZ2VzLmNvbHMuYnJldyRzdWJsaW5lYWdlKSArCiAgdGhlbWUudGV4dC5zaXplICsgdGhlbWUobGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjUsImxpbmUiKSkKCnBsb3Quc3Vic2FtcGxlZC5NTC50aXBzLjNwdi5jb3VudHJ5LmRhdGVzLnN1Ymxpbi50cmVlCmBgYApkbyByb290MnRpcCBmb3Igc2Vjb25kIHN1YnNhbXBsZWQgdHJlZQpgYGB7cn0KcC5zdWJzYW1wbGVkLk1MLnRpcHMuM3B2LmNvdW50cnkuZGF0ZXMuc3VibGluLnJvb3QydGlwIDwtIHBsb3RSb290VG9UaXAoc3Vic2FtcGxlZC5NTC50aXBzLjNwdi5jb3VudHJ5LmRhdGVzLnN1Ymxpbi50cmVlLCBUUEEubWV0YTEuMi5waW5lY29uZS5oYXZlZGF0ZXNbLGMoIlNhbXBsZV9OYW1lIiwiU2FtcGxlX1llYXIiKV0pCgoKcGxvdF9ncmlkKHAuc3Vic2FtcGxlZC5NTC50aXBzLjNwdi5jb3VudHJ5LmRhdGVzLnN1Ymxpbi5yb290MnRpcCwgcC5zdWJzYW1wbGVkLk1MLnRpcHMuM3B2LmNvdW50cnkuZGF0ZXMuc3VibGluLnJvb3QydGlwICsgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMTQwMCwyMDIwKSkgKyBjb29yZF9jYXJ0ZXNpYW4oeGxpbT1jKDE0MDAsMjAyMCksIHlsaW09YygwLDguNWUtNSkpLCBuY29sPTIpCmBgYAoKUGxvdCByZXBlYXQgc3Vic2V0dGVkIHRyZWUgYW5kIHNreWxpbmUgaW5mbwoKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcmVwZWF0LnN1YnNhbXBsZWQuc2t5bGluZS50cmVlIDwtIHJlYWQuYmVhc3QocmVwZWF0LnN1YnNhbXBsZWQuc2t5bGluZS50cmVlLmZpbGUpCnJlcGVhdC5zdWJzYW1wbGVkLnNreWxpbmUudHJlZS5kYXRhIDwtIGRhdGEuZnJhbWUoZm9ydGlmeShyZXBlYXQuc3Vic2FtcGxlZC5za3lsaW5lLnRyZWUpLHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQoKIyBCRUFTVCB0aXBuYW1lcyBoYXZlIGRhdGUgaW5jbHVkZWQgLSBsZXRzIHJlbW92ZSB0aGF0IGZvciBwbG90dGluZyB3aXRoIG1ldGFkYXRhCnJlcGVhdC5zdWJzYW1wbGVkLnNreWxpbmUudHJlZS50aXBuYW1lcyA8LSBkYXRhLmZyYW1lKGJlYXN0Lm5hbWU9cmVwZWF0LnN1YnNhbXBsZWQuc2t5bGluZS50cmVlQHBoeWxvJHRpcC5sYWJlbCxzdHJpbmdzQXNGYWN0b3JzID0gRikKcmVwZWF0LnN1YnNhbXBsZWQuc2t5bGluZS50cmVlLnRpcG5hbWVzJG1ldGEubmFtZSA8LSBnc3ViKCJcXHwuKyQiLCIiLCByZXBlYXQuc3Vic2FtcGxlZC5za3lsaW5lLnRyZWUudGlwbmFtZXMkYmVhc3QubmFtZSkKcmVwZWF0LnN1YnNhbXBsZWQuc2t5bGluZS50cmVlQHBoeWxvJHRpcC5sYWJlbCA8LSByZXBlYXQuc3Vic2FtcGxlZC5za3lsaW5lLnRyZWUudGlwbmFtZXMkbWV0YS5uYW1lCgojIEJ1aWxkIHBsb3QKcmVwZWF0LnN1YnNhbXBsZWQuc2t5bGluZS5wbG90MSA8LSBnZ3RyZWUocmVwZWF0LnN1YnNhbXBsZWQuc2t5bGluZS50cmVlLG1yc2Q9IjIwMTktMDYtMDEiLGxhZGRlcml6ZSA9IFQpICsgCiAgdGhlbWVfdHJlZTIoKSArCiAgIyBBZGQgZGF0ZSBsaW5lcyBmb3IgZWFzeSBpbnRlcnByZXRhdGlvbiAgCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDEzMDAsMTQwMCwxNTAwLDE2MDAsMTcwMCwxODAwLDE4NTAsMTkwMCwxOTI1LDE5NTAsMTk3NSwyMDAwLDIwMjApLCBtaW5vcl9icmVha3M9c2VxKDE5NTAsIDIwMjAsIDUpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciAgID0gZWxlbWVudF9saW5lKGNvbG9yPSJncmV5NTAiLCBzaXplPS4yKSwKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yICAgPSBlbGVtZW50X2xpbmUoY29sb3I9ImdyZXk4NSIsIHNpemU9LjIpLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yLnkgPSBlbGVtZW50X2JsYW5rKCkpIAojIEFkZCBwb3N0ZXJpb3Igc3VwcG9ydCBhcyBub2RlIHBvaW50cwpyZXBlYXQuc3Vic2FtcGxlZC5za3lsaW5lLnBsb3QxIDwtIHJlcGVhdC5zdWJzYW1wbGVkLnNreWxpbmUucGxvdDEgKyBnZW9tX3BvaW50MihhZXMoc3Vic2V0PSghaXNUaXAgJiBhcy5udW1lcmljKHBvc3Rlcmlvcik+MC44KSksY29sb3I9ImdyYXk2MCIsc2l6ZT0yLjUsYWxwaGE9MC41LCBzaGFwZT0xOCkgKyAKICBnZW9tX3BvaW50MihhZXMoc3Vic2V0PSghaXNUaXAgJiBhcy5udW1lcmljKHBvc3Rlcmlvcik+MC45MSkpLGNvbG9yPSJncmF5NDAiLHNpemU9Mi41LHNoYXBlPTE4LGFscGhhPTAuNSkgKyAKICBnZW9tX3BvaW50MihhZXMoc3Vic2V0PSghaXNUaXAgJiBhcy5udW1lcmljKHBvc3Rlcmlvcik+PTAuOTYpKSxjb2xvcj0iYmxhY2siLHNpemU9Mi41LHNoYXBlPTE4LGFscGhhPTAuNSkKCiMgUGxvdCA5NSUgSFBEIGludGVydmFscyAtIGdlb21fcmFuZ2Ugc2VlbXMgdW5hYmxlIHRvIGRvIGNvcnJlY3RseSB3aXRoIHRoaXMgdHJlZSAoa25vd24gYnVnIGZvciB0aXAgZGF0ZWQgdHJlZXMpLCBzbyBleHRyYWN0IGRhdGEgYW5kIHBsb3QgdXNpbmcgZ2VvbV9zZWdtZW50CnJlcC5taW5tYXggPC0gdChtYXRyaXgodW5saXN0KHJlcGVhdC5zdWJzYW1wbGVkLnNreWxpbmUudHJlZS5kYXRhWyFpcy5uYShyZXBlYXQuc3Vic2FtcGxlZC5za3lsaW5lLnRyZWUuZGF0YSRoZWlnaHRfMC45NV9IUEQpLCJoZWlnaHRfMC45NV9IUEQiXSksbnJvdz0yKSkKcmVwLmJhcl9kZiA8LSBkYXRhLmZyYW1lKG5vZGVfaWQ9cmVwZWF0LnN1YnNhbXBsZWQuc2t5bGluZS50cmVlLmRhdGFbIWlzLm5hKHJlcGVhdC5zdWJzYW1wbGVkLnNreWxpbmUudHJlZS5kYXRhJGhlaWdodF8wLjk1X0hQRCksIm5vZGUiXSxhcy5kYXRhLmZyYW1lKHJlcC5taW5tYXgpKQpuYW1lcyhyZXAuYmFyX2RmKSA8LSBjKCdub2RlX2lkJywnbWluJywnbWF4JykgCnJlcC5iYXJfZGYgPC0gcmVwLmJhcl9kZiAlPiUgZmlsdGVyKG5vZGVfaWQgPiBOdGlwKHJlcGVhdC5zdWJzYW1wbGVkLnNreWxpbmUudHJlZUBwaHlsbykpCnJlcC5iYXJfZGYgPC0gcmVwLmJhcl9kZiAlPiUgbGVmdF9qb2luKHJlcGVhdC5zdWJzYW1wbGVkLnNreWxpbmUucGxvdDEkZGF0YSwgYnk9Yygnbm9kZV9pZCc9J25vZGUnKSkgJT4lIHNlbGVjdChub2RlX2lkLG1pbixtYXgseSkKcmVwLm1yY2QuZGVjaW1hbCA8LSBkZWNpbWFsX2RhdGUoYXMuRGF0ZSgiMjAxOS0wNi0wMSIsIiVZLSVtLSVkIikpCnJlcGVhdC5zdWJzYW1wbGVkLnNreWxpbmUucGxvdDEgPC0gcmVwZWF0LnN1YnNhbXBsZWQuc2t5bGluZS5wbG90MSArIGdlb21fc2VnbWVudChhZXMoeD1yZXAubXJjZC5kZWNpbWFsLW1heCwgeT15LCB4ZW5kPXJlcC5tcmNkLmRlY2ltYWwtbWluLCB5ZW5kPXkpLCBkYXRhPXJlcC5iYXJfZGYsIGNvbG9yPSdyZWQnLCBhbHBoYT0wLjIsIHNpemU9Mi4yNSkKcmVwZWF0LnN1YnNhbXBsZWQuc2t5bGluZS5wbG90MSA8LSByZXBlYXQuc3Vic2FtcGxlZC5za3lsaW5lLnBsb3QxICsgbmV3X3NjYWxlX2ZpbGwoKQoKIyBBZGQgbWFya2VycyBhZnRlciAyMDAwCnJlcGVhdC5zdWJzYW1wbGVkLnNreWxpbmUucGxvdDEgPC0gcmVwZWF0LnN1YnNhbXBsZWQuc2t5bGluZS5wbG90MSArIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDIwMDAsIGNvbG9yPSdibHVlJywgYWxwaGE9MC41KSArIAogIGFubm90YXRlKCJyZWN0Iix4bWluPTIwMDAseG1heD0yMDIwLHltaW49LTEseW1heD0xNzAsYWxwaGE9MC4xLCBmaWxsPSdibHVlJykKCnJlcGVhdC5zdWJzYW1wbGVkLnNreWxpbmUucGxvdDEgKyBnZW9tX3RpcGxhYihzaXplPTEuNSwgYWxpZ249VCkKCgoKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIFNreWxpbmUKcmVwLmJlYXN0LnN1YnRyZWUuc2t5bGluZSA8LSByZWFkLnRhYmxlKHJlcGVhdC5zdWJzYW1wbGVkLnNreWxpbmUuZGF0YS5maWxlLCBzZXA9Ilx0IiwgY2hlY2submFtZXM9RiwgY29tbWVudC5jaGFyPSIiLCBoZWFkZXI9VCwgc3RyaW5nc0FzRmFjdG9ycz1GKQpwLnJlcC5iZWFzdC5zdWJ0cmVlLnNreWxpbmUgPC0gZ2dwbG90KHJlcC5iZWFzdC5zdWJ0cmVlLnNreWxpbmUsIGFlcyhUaW1lLE1lZGlhbikpICsgCiAgZ2VvbV9saW5lKCkgKyBnZW9tX3JpYmJvbihhZXMoeW1pbj1Mb3dlciwgeW1heD1VcHBlciksIGFscGhhPTAuMiwgZmlsbD0nYmxhY2snKSArCiAgdGhlbWVfbGlnaHQoKSArIAogIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YyhzZXEoMTc0MCwyMDIwLDIwKSksIGV4cGFuZD1jKDAuMDEsMC4wMSkpICsgc2NhbGVfeV9sb2cxMCgpICsgCiAgY29vcmRfY2FydGVzaWFuKHg9YygxNzUwLDIwMjApLCB5PWMoNTAsMzAwMCkpICsgCiAgdGhlbWUudGV4dC5zaXplICsgbGFicyh5PSJSZWxhdGl2ZSBnZW5ldGljIGRpdmVyc2l0eSIsIHg9IlllYXIiKSArIAogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDIwMDAsIGNvbG9yPSdibHVlJywgYWxwaGE9MC41KSArIGFubm90YXRlKCJyZWN0Iix4bWluPTIwMDAseG1heD0yMDIwLHltaW49MCx5bWF4PTEwMDAwLGFscGhhPTAuMSwgZmlsbD0nYmx1ZScpCgojIExpbmVhZ2VzCnJlcC5iZWFzdC5zdWJ0cmVlLnNreWxpbmUubGluZWFnZXMgPC0gcmVhZC50YWJsZShyZXBlYXQuc3Vic2FtcGxlZC5za3lsaW5lLmxpbmVhZ2VzLmRhdGEuZmlsZSwgc2VwPSJcdCIsIGNoZWNrLm5hbWVzPUYsIGNvbW1lbnQuY2hhcj0iIiwgaGVhZGVyPVQsIHN0cmluZ3NBc0ZhY3RvcnM9RikKcC5yZXAuYmVhc3Quc3VidHJlZS5za3lsaW5lLmxpbmVhZ2VzIDwtIGdncGxvdChyZXAuYmVhc3Quc3VidHJlZS5za3lsaW5lLmxpbmVhZ2VzLCBhZXMoVGltZSxNZWRpYW4pKSArIAogIGdlb21fbGluZSgpICsgZ2VvbV9yaWJib24oYWVzKHltaW49TG93ZXIsIHltYXg9VXBwZXIpLCBhbHBoYT0wLjIsIGZpbGw9J2JsYWNrJykgKwogIHRoZW1lX2xpZ2h0KCkgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoc2VxKDE3NDAsMjAyMCwyMCkpLCBleHBhbmQ9YygwLjAxLDAuMDEpKSArIHNjYWxlX3lfbG9nMTAoKSArIAogIGNvb3JkX2NhcnRlc2lhbih4PWMoMTc1MCwyMDIwKSwgeT1jKDEsMzAwKSkgKyAKICB0aGVtZS50ZXh0LnNpemUgKyBsYWJzKHk9IkxpbmVhZ2VzIiwgeD0iWWVhciIpICsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMjAwMCwgY29sb3I9J2JsdWUnLCBhbHBoYT0wLjUpICsgYW5ub3RhdGUoInJlY3QiLHhtaW49MjAwMCx4bWF4PTIwMjAseW1pbj0wLHltYXg9NTAwLGFscGhhPTAuMSwgZmlsbD0nYmx1ZScpCiNwLnJlcC5iZWFzdC5zdWJ0cmVlLnNreWxpbmUubGluZWFnZXMKCgoKIyBNYWtlIGNvbWJpbmVkIHBsb3QKcmVwLnNreWxpbmUucm93IDwtIHBsb3RfZ3JpZChOVUxMLHAucmVwLmJlYXN0LnN1YnRyZWUuc2t5bGluZSxOVUxMLCBuY29sPTMsIHJlbF93aWR0aHMgPSBjKDEsMywxKSkKcmVwLmxpbmVhZ2Uucm93IDwtIHBsb3RfZ3JpZChOVUxMLHAucmVwLmJlYXN0LnN1YnRyZWUuc2t5bGluZS5saW5lYWdlcyxOVUxMLCBuY29sPTMsIHJlbF93aWR0aHMgPSBjKDEsMywxKSkKI3JlcC5ib3RoLnNreWxpbmUubGluZWFnZS5yb3dzIDwtIHBsb3RfZ3JpZChyZXAuc2t5bGluZS5yb3csIHJlcC5saW5lYWdlLnJvdywgYWxpZ249VCwgbmNvbD0xLCBsYWJlbHM9YygnQicsJ0MnKSkKcmVwLmJvdGguc2t5bGluZS5saW5lYWdlLnJvd3MgPC0gcGxvdF9ncmlkKHJlcC5za3lsaW5lLnJvdywgYWxpZ249VCwgbmNvbD0xLCBsYWJlbHM9YygnQicpLGxhYmVsX3NpemU9MTEpCgojcGxvdC5iZWFzdC53aXRoLnNreWxpbmUucmVwZWF0IDwtIHBsb3RfZ3JpZChyZXBlYXQuc3Vic2FtcGxlZC5za3lsaW5lLnBsb3QxICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSdub25lJyksIHJlcC5ib3RoLnNreWxpbmUubGluZWFnZS5yb3dzLCBuY29sPTEsIGFsaWduPVQsIHJlbF9oZWlnaHRzID0gYygyLDIpLGxhYmVscz1jKCdBJywnJyksIGxhYmVsX3NpemU9MTEpCgpwbG90LmJlYXN0LndpdGguc2t5bGluZS5yZXBlYXQgPC0gcGxvdF9ncmlkKHJlcGVhdC5zdWJzYW1wbGVkLnNreWxpbmUucGxvdDEgKyB0aGVtZShsZWdlbmQucG9zaXRpb249J25vbmUnKSwgcmVwLmJvdGguc2t5bGluZS5saW5lYWdlLnJvd3MsIG5jb2w9MSwgYWxpZ249VCwgcmVsX2hlaWdodHMgPSBjKDMsMSksbGFiZWxzPWMoJ0EnLCcnKSwgbGFiZWxfc2l6ZT0xMSkKCgoKI3Bsb3QuYmVhc3Qud2l0aC5za3lsaW5lIDwtIHBsb3RfZ3JpZChUUEEuYmVhc3QucGxvdDEubWV0YSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0nbm9uZScpLCBza3lsaW5lLnJvdywgbmNvbD0xLCBhbGlnbj1ULCByZWxfaGVpZ2h0cyA9IGMoMiwxKSxsYWJlbHM9YygnQScsJ0InKSwgbGFiZWxfc2l6ZT0xMSkKI2JlYXN0LmxlZ2VuZC5jb21iaW5lZCA8LSBwbG90X2dyaWQoYmVhc3QueWVhci5sZWdlbmQsIE5VTEwsIG5jb2w9MSwgcmVsX2hlaWdodHM9YygzLDEpKQoKCiNDYWlybzo6Q2Fpcm8oZmlsZT1wYXN0ZTAoRmlndXJlX291dHB1dF9kaXJlY3RvcnksICJTdXBwbGVtZW50YXJ5X0ZpZ3VyZTE3X3N1YnNhbXBsZTItMTY4X0JFQVNUX1N0cmljdENTa3lsaW5lXzAyLTIwMjEuc3ZnIiksIHdpZHRoID0gODAwLCBoZWlnaHQgPSA4MDAsdHlwZT0ic3ZnIix1bml0cyA9ICJwdCIpCnBsb3QuYmVhc3Qud2l0aC5za3lsaW5lLnJlcGVhdCAKI2Rldi5vZmYoKQoKYGBgCgpQbG90dGluZyBSb290LXRvLXRpcApgYGB7cn0KIyBEZWZpbmUgZnVuY3Rpb24KcGxvdC5zdWJ0cmVlLlIyVCA8LSBmdW5jdGlvbihtYWludHJlZSwgdGlwcywgZGF0ZXMuZGYpewogIHN1YnRyZWUudGVtcCAgPC0gYXBlOjprZWVwLnRpcChtYWludHJlZSwgYXMuY2hhcmFjdGVyKHRpcHMpKQogIHBsb3RSb290VG9UaXAoc3VidHJlZS50ZW1wLCBkYXRlcy5kZlssYygiU2FtcGxlX05hbWUiLCJTYW1wbGVfWWVhciIpXSkKICBwbG90X2dyaWQoZ2d0cmVlKHN1YnRyZWUudGVtcCkscGxvdFJvb3RUb1RpcChzdWJ0cmVlLnRlbXAsIGRhdGVzLmRmWyxjKCJTYW1wbGVfTmFtZSIsIlNhbXBsZV9ZZWFyIildKSxuY29sPTIpCn0KCmBgYAoKCkZ1bGwgdHJlZSBkYXRhc2V0IGZvciBCRUFTVDEvMjoKYGBge3J9CmZ1bGwuYmVhc3QyLnRyZWUgPC0gcmVhZC5iZWFzdChmdWxsLmJlYXN0Mi50cmVlLmZpbGUpCnRyZWUuc3Vic2FtcGxlZC5NTC50aXBzLmZ1bGwuZGF0YS5mb3IuYmVhc3QyIDwtIChhcGU6OmtlZXAudGlwKFRQQS5NTHRyZWUsIGdzdWIoIlxcfC4rJCIsIiIsZnVsbC5iZWFzdDIudHJlZUBwaHlsbyR0aXAubGFiZWwsIHBlcmwgPVQpKSkKCnRyZWUuc3Vic2FtcGxlZC5NTC50aXBzLmZ1bGwuZGF0YS5mb3IuYmVhc3QyLnIydCA8LSBwbG90LnN1YnRyZWUuUjJUKHRyZWUuc3Vic2FtcGxlZC5NTC50aXBzLmZ1bGwuZGF0YS5mb3IuYmVhc3QyLCBnc3ViKCJcXHwuKyQiLCIiLGZ1bGwuYmVhc3QyLnRyZWVAcGh5bG8kdGlwLmxhYmVsKSwgVFBBLm1ldGExLjIucGluZWNvbmUuaGF2ZWRhdGVzWyxjKCJTYW1wbGVfTmFtZSIsIlNhbXBsZV9ZZWFyIildKQoKCiNDYWlybzo6Q2Fpcm8oZmlsZT1wYXN0ZTAoRmlndXJlX291dHB1dF9kaXJlY3RvcnksICJTdXBwbGVtZW50YXJ5X0ZpZ3VyZTE4X19NTC10cmVlLmZ1bGx0cmVlNTIwLXdpdGgtcm9vdDJ0aXBfMDItMjAyMS5zdmciKSwgd2lkdGggPSA4MDAsIGhlaWdodCA9IDYwMCx0eXBlPSJzdmciLHVuaXRzID0gInB0IikKdHJlZS5zdWJzYW1wbGVkLk1MLnRpcHMuZnVsbC5kYXRhLmZvci5iZWFzdDIucjJ0CiNkZXYub2ZmKCkKCmBgYAoKCgpcClB1bGwgaW4gZGF0YSBmb3IgZnVsbCBCRUFTVDIgdHJlZSBcClwKCkZ1bGwgQmVhc3QgdHJlZQpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTEyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpmdWxsLmJlYXN0Mi50cmVlIDwtIHJlYWQuYmVhc3QoZnVsbC5iZWFzdDIudHJlZS5maWxlKQpmdWxsLmJlYXN0Mi50cmVlLmRhdGEgPC0gZGF0YS5mcmFtZShmb3J0aWZ5KGZ1bGwuYmVhc3QyLnRyZWUpLHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQoKCiMgTGV0cyBzb3J0IG91dCB0aGUgZGF0ZSBvZiB2YXJpb3VzIGV2ZW50cyAtIHJlbGF0ZSBldmVyeXRoaW5nIGluIHllYXJzCmZ1bGwuYmVhc3QyLnRyZWUuZGF0YSRtcmNhLm1lZGlhbiA8LSAyMDE5LjUgLSBmdWxsLmJlYXN0Mi50cmVlLmRhdGEkaGVpZ2h0X21lZGlhbgpmdWxsLmJlYXN0Mi50cmVlLmRhdGEkeWVhciA8LSBhcy5udW1lcmljKHJvdW5kKDIwMTkuNSAtIGZ1bGwuYmVhc3QyLnRyZWUuZGF0YSRoZWlnaHRfbWVkaWFuLDApKQoKZnVsbC5iZWFzdDIudHJlZS5kYXRhJG1yY2EuOTVoaWdoIDwtIHJvdW5kKDIwMTkuNSAtIHNhcHBseSgxOm5yb3coZnVsbC5iZWFzdDIudHJlZS5kYXRhKSxmdW5jdGlvbih4KSBhcy5udW1lcmljKHVubGlzdChmdWxsLmJlYXN0Mi50cmVlLmRhdGFbeCwiaGVpZ2h0XzAuOTVfSFBEIl0pKVsxXSkpCgpmdWxsLmJlYXN0Mi50cmVlLmRhdGEkbXJjYS45NWxvdyA8LSByb3VuZCgyMDE5LjUgLSBzYXBwbHkoMTpucm93KGZ1bGwuYmVhc3QyLnRyZWUuZGF0YSksZnVuY3Rpb24oeCkgYXMubnVtZXJpYyh1bmxpc3QoZnVsbC5iZWFzdDIudHJlZS5kYXRhW3gsImhlaWdodF8wLjk1X0hQRCJdKSlbMl0pKQoKCiMgSm9pbiBtZXRhZGF0YQpmdWxsLmJlYXN0Mi50cmVlLmRhdGEkU2FtcGxlX05hbWUgPC0gZ3N1YigiXFx8LiskIiwiIiwgZnVsbC5iZWFzdDIudHJlZS5kYXRhJGxhYmVsKQpmdWxsLmJlYXN0Mi50cmVlLmRhdGEubWV0YSA8LSBwbHlyOjpqb2luKGZ1bGwuYmVhc3QyLnRyZWUuZGF0YSwgVFBBLm1ldGExLjIucGluZWNvbmVbLGMoIlNhbXBsZV9OYW1lIiwgIkdlb19Db3VudHJ5IiwiVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UiLCJTYW1wbGVfWWVhciIpXSwgYnk9IlNhbXBsZV9OYW1lIiwgdHlwZT0ibGVmdCIpCgpmdWxsLmJlYXN0Mi50cmVlLmRhdGEubWV0YSA8LSBmdWxsLmJlYXN0Mi50cmVlLmRhdGEubWV0YVtmdWxsLmJlYXN0Mi50cmVlLmRhdGEubWV0YSRpc1RpcD09VCxdCmBgYAoKCgpFeHRyYWN0IHNvbWUga2V5IGRhdGVzCgpgYGB7cn0KIyMjIyMKIyMjIyMjIyMjIyMjI2Z1bGwuYmVhc3QyLnRyZWUuZGF0YS50aXAgPC0gZnVsbC5iZWFzdDIudHJlZS5kYXRhW2Z1bGwuYmVhc3QyLnRyZWUuZGF0YSRpc1RpcF0KIyMjIyMjCkV4cGFuZGVkLnN1YmxpbmVhZ2VzIDwtIGRhdGEuZnJhbWUoU3VibGluZWFnZT1jKDEsMiw4LDE0KSwgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCgojIFJ1biBsb29wIHRvIGV4dHJhY3QgTVJDQSBub2RlIGZvciBlYWNoIHN1YmxpbmVhZ2UKRXhwYW5kZWQuc3VibGluZWFnZS5ub2RlcyA8LSBOVUxMCmZvciAoY3VycmVudC5zdWJsaW5lYWdlLmV4cDEgaW4gRXhwYW5kZWQuc3VibGluZWFnZXMkU3VibGluZWFnZSkgewogIEV4cGFuZGVkLnN1YmxpbmVhZ2Uubm9kZXMgPC0gYyhFeHBhbmRlZC5zdWJsaW5lYWdlLm5vZGVzLCBhcGU6OmdldE1SQ0EoYXMucGh5bG8oZnVsbC5iZWFzdDIudHJlZSksYXMuY2hhcmFjdGVyKGZ1bGwuYmVhc3QyLnRyZWUuZGF0YS5tZXRhW2Z1bGwuYmVhc3QyLnRyZWUuZGF0YS5tZXRhJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlPT1jdXJyZW50LnN1YmxpbmVhZ2UuZXhwMSwiU2FtcGxlX05hbWUiXSkpKQp9CkV4cGFuZGVkLnN1YmxpbmVhZ2VzJG5vZGUgPC0gRXhwYW5kZWQuc3VibGluZWFnZS5ub2RlcwoKCiMgUGxvdCB0cmVlIHdpdGggbm9kZSBsYWJlbHMgKHRvIHZpc3VhbGlzZSBhbmQgaWRlbnRpZnkga2V5IG5vZGVzKQpnZ3RyZWUoZnVsbC5iZWFzdDIudHJlZSkgKyBnZW9tX3RleHQyKGFlcyhzdWJzZXQ9IWlzVGlwLCBsYWJlbD1ub2RlKSwgaGp1c3Q9LS4zLCBzaXplPTIuNSwgY29sb3I9ImJsdWUiKSAKCiMgU3BsaXQgc3VibGluZWFnZSAxIGluIHRoaXMgdHJlZSBjcmVhdGVzIGEgcHJvYmxlbS4gQ2hhbmdlIGl0IHRvIDUyOCAoTVJDQSBvZiBtYWluIGNsYWRlKQpFeHBhbmRlZC5zdWJsaW5lYWdlc1tFeHBhbmRlZC5zdWJsaW5lYWdlcyRTdWJsaW5lYWdlPT0xLCJub2RlIl0gPC0gNTI4CgoKCiMgRXh0cmFjdCBkYXRlcyBmb3IgdGhlIE1SQ0FzIC0gd2hlbiBkaWQgdGhvc2Ugc3VibGluZWFnZXMgZmlyc3QgYXJpc2U/IFByZXR0eSBvbGQhCnBseXI6OmpvaW4oRXhwYW5kZWQuc3VibGluZWFnZXMsIGZ1bGwuYmVhc3QyLnRyZWUuZGF0YVssYygibm9kZSIsIm1yY2EubWVkaWFuIiwieWVhciIsIm1yY2EuOTVoaWdoIiwibXJjYS45NWxvdyIpXSwgYnk9Im5vZGUiKQoKCmdndHJlZShmdWxsLmJlYXN0Mi50cmVlLG1yc2Q9IjIwMTktMDYtMDEiLGxhZGRlcml6ZSA9IFQpICsgZ2VvbV90ZXh0MihhZXMoc3Vic2V0PSFpc1RpcCwgbGFiZWw9bm9kZSksIGhqdXN0PS0uMywgc2l6ZT0yKSArCiAgZ2VvbV9wb2ludDIoYWVzKHN1YnNldD0obm9kZSAlaW4lIEV4cGFuZGVkLnN1YmxpbmVhZ2VzJG5vZGUpKSxjb2xvcj0iYmx1ZSIpICsKICBnZ3RpdGxlKCJSZWQgbm9kZXMgaW5kaWNhdGUgTVJDQSBmb3IgZWFjaCBzdWJsaW5lYWdlIikKCmBgYAoKTGV0cyBwbG90IHRoZSBCRUFTVCB0cmVlCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9MTIsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgQkVBU1QgdGlwbmFtZXMgaGF2ZSBkYXRlIGluY2x1ZGVkIC0gbGV0cyByZW1vdmUgdGhhdCBmb3IgcGxvdHRpbmcgd2l0aCBtZXRhZGF0YQpmdWxsLmJlYXN0Mi50aXBuYW1lcyA8LSBkYXRhLmZyYW1lKGJlYXN0Lm5hbWU9ZnVsbC5iZWFzdDIudHJlZUBwaHlsbyR0aXAubGFiZWwsc3RyaW5nc0FzRmFjdG9ycyA9IEYpCmZ1bGwuYmVhc3QyLnRpcG5hbWVzJG1ldGEubmFtZSA8LSBnc3ViKCJcXHwuKyQiLCIiLCBmdWxsLmJlYXN0Mi50aXBuYW1lcyRiZWFzdC5uYW1lKQpmdWxsLmJlYXN0Mi50cmVlQHBoeWxvJHRpcC5sYWJlbCA8LSBmdWxsLmJlYXN0Mi50aXBuYW1lcyRtZXRhLm5hbWUKI1RQQS5iZWFzdC50cmVlQHBoeWxvJHRpcC5sYWJlbAoKCiMgQnVpbGQgcGxvdApmdWxsLmJlYXN0Mi50cmVlLnBsb3QxIDwtIGdndHJlZShmdWxsLmJlYXN0Mi50cmVlLG1yc2Q9IjIwMTktMDYtMDEiLGxhZGRlcml6ZSA9IFQpICsgCiAgdGhlbWVfdHJlZTIoKSArCiAgIyBBZGQgZGF0ZSBsaW5lcyBmb3IgZWFzeSBpbnRlcnByZXRhdGlvbiAgCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDEzMDAsMTQwMCwxNTAwLDE2MDAsMTcwMCwxODAwLDE4NTAsMTkwMCwxOTI1LDE5NTAsMTk3NSwyMDAwLDIwMjApLCBtaW5vcl9icmVha3M9c2VxKDE5NTAsIDIwMjAsIDUpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciAgID0gZWxlbWVudF9saW5lKGNvbG9yPSJncmV5NTAiLCBzaXplPS4yKSwKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yICAgPSBlbGVtZW50X2xpbmUoY29sb3I9ImdyZXk4NSIsIHNpemU9LjIpLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yLnkgPSBlbGVtZW50X2JsYW5rKCkpIAojIEFkZCBwb3N0ZXJpb3Igc3VwcG9ydCBhcyBub2RlIHBvaW50cwpmdWxsLmJlYXN0Mi50cmVlLnBsb3QxIDwtIGZ1bGwuYmVhc3QyLnRyZWUucGxvdDEgKyBnZW9tX3BvaW50MihhZXMoc3Vic2V0PSghaXNUaXAgJiBhcy5udW1lcmljKHBvc3Rlcmlvcik+MC44KSksY29sb3I9ImdyYXk2MCIsc2l6ZT0yLjUsYWxwaGE9MC41LCBzaGFwZT0xOCkgKyAKICBnZW9tX3BvaW50MihhZXMoc3Vic2V0PSghaXNUaXAgJiBhcy5udW1lcmljKHBvc3Rlcmlvcik+MC45MSkpLGNvbG9yPSJncmF5NDAiLHNpemU9Mi43NSxzaGFwZT0xOCxhbHBoYT0wLjUpICsgCiAgZ2VvbV9wb2ludDIoYWVzKHN1YnNldD0oIWlzVGlwICYgYXMubnVtZXJpYyhwb3N0ZXJpb3IpPj0wLjk2KSksY29sb3I9ImJsYWNrIixzaXplPTIuNzUsc2hhcGU9MTgsYWxwaGE9MC41KSArCiAgICBnZW9tX3Jvb3RlZGdlKHJvb3RlZGdlPTUwKQoKCiMgUGxvdCA5NSUgSFBEIGludGVydmFscyAtIGdlb21fcmFuZ2Ugc2VlbXMgdW5hYmxlIHRvIGRvIGNvcnJlY3RseSB3aXRoIHRoaXMgdHJlZSAoa25vd24gYnVnIGZvciB0aXAgZGF0ZWQgdHJlZXMpLCBzbyBleHRyYWN0IGRhdGEgYW5kIHBsb3QgdXNpbmcgZ2VvbV9zZWdtZW50Cm1pbm1heC5mdWxsdHJlZSA8LSB0KG1hdHJpeCh1bmxpc3QoZnVsbC5iZWFzdDIudHJlZS5kYXRhWyFpcy5uYShmdWxsLmJlYXN0Mi50cmVlLmRhdGEkaGVpZ2h0XzAuOTVfSFBEKSwiaGVpZ2h0XzAuOTVfSFBEIl0pLG5yb3c9MikpCmJhcl9kZi5mdWxsdHJlZSA8LSBkYXRhLmZyYW1lKG5vZGVfaWQ9ZnVsbC5iZWFzdDIudHJlZS5kYXRhWyFpcy5uYShmdWxsLmJlYXN0Mi50cmVlLmRhdGEkaGVpZ2h0XzAuOTVfSFBEKSwibm9kZSJdLGFzLmRhdGEuZnJhbWUobWlubWF4LmZ1bGx0cmVlKSkKbmFtZXMoYmFyX2RmLmZ1bGx0cmVlKSA8LSBjKCdub2RlX2lkJywnbWluJywnbWF4JykgCmJhcl9kZi5mdWxsdHJlZSA8LSBiYXJfZGYuZnVsbHRyZWUgJT4lIGZpbHRlcihub2RlX2lkID4gTnRpcChmdWxsLmJlYXN0Mi50cmVlQHBoeWxvKSkKYmFyX2RmLmZ1bGx0cmVlIDwtIGJhcl9kZi5mdWxsdHJlZSAlPiUgbGVmdF9qb2luKGZ1bGwuYmVhc3QyLnRyZWUucGxvdDEkZGF0YSwgYnk9Yygnbm9kZV9pZCc9J25vZGUnKSkgJT4lIHNlbGVjdChub2RlX2lkLG1pbixtYXgseSkKbXJjZC5kZWNpbWFsLmZ1bGx0cmVlIDwtIGRlY2ltYWxfZGF0ZShhcy5EYXRlKCIyMDE5LTA2LTAxIiwiJVktJW0tJWQiKSkKZnVsbC5iZWFzdDIudHJlZS5wbG90MSA8LSBmdWxsLmJlYXN0Mi50cmVlLnBsb3QxICsgZ2VvbV9zZWdtZW50KGFlcyh4PW1yY2QuZGVjaW1hbC5mdWxsdHJlZS1tYXgsIHk9eSwgeGVuZD1tcmNkLmRlY2ltYWwuZnVsbHRyZWUtbWluLCB5ZW5kPXkpLCBkYXRhPWJhcl9kZi5mdWxsdHJlZSwgY29sb3I9J3JlZCcsIGFscGhhPTAuMiwgc2l6ZT0xLjUpCgpmdWxsLmJlYXN0Mi50cmVlLnBsb3QxIDwtIGZ1bGwuYmVhc3QyLnRyZWUucGxvdDEgKyBuZXdfc2NhbGVfZmlsbCgpCiNmdWxsLmJlYXN0Mi50cmVlLnBsb3QxICMrIGdlb21fdGlwbGFiKHNpemU9MiwgYWxpZ249VCkKCiMgQWRkIE1ldGFkYXRhCmZ1bGwuYmVhc3QyLnRyZWUucGxvdDEubWV0YSA8LSBnaGVhdG1hcChmdWxsLmJlYXN0Mi50cmVlLnBsb3QxLAogICAgICAgICAgICAgICBkYXRhLmZyYW1lKHJvdy5uYW1lcz1UUEEubWV0YTEuMi5waW5lY29uZSRTYW1wbGVfTmFtZSwgU3VibGluZWFnZT1UUEEubWV0YTEuMi5waW5lY29uZSRUUEEucGluZWNvbmUuc3VibGluZWFnZSksIGNvbG9yPU5VTEwsd2lkdGg9MC4wNSwgb2Zmc2V0PTIsY29sbmFtZXNfYW5nbGU9MCxjb2xuYW1lc19vZmZzZXRfeT0tMS41LCBmb250LnNpemU9Mi4yNSwpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZT0iU3VibGluZWFnZSIsdmFsdWVzPXN1YmxpbmVhZ2VzLmNvbHMuYnJldyRzdWJsaW5lYWdlLmNvbHMsIGJyZWFrcz1zdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZSkgKwogIHRoZW1lLnRleHQuc2l6ZQpmdWxsLmJlYXN0Mi50cmVlLnBsb3QxLm1ldGEgPC0gZnVsbC5iZWFzdDIudHJlZS5wbG90MS5tZXRhICsgbmV3X3NjYWxlX2ZpbGwoKQoKZnVsbC5iZWFzdDIudHJlZS5wbG90MS5tZXRhIDwtIGdoZWF0bWFwKGZ1bGwuYmVhc3QyLnRyZWUucGxvdDEubWV0YSxUUEEucmF3c2VxLmNvdW50cmllcy5wLCBjb2xvcj1OVUxMLHdpZHRoPTAuMDUsb2Zmc2V0PTM2LCBjb2xuYW1lc19hbmdsZT0wLGNvbG5hbWVzX29mZnNldF95PS0xLjUsIGZvbnQuc2l6ZT0yLjI1KSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWU9IkNvdW50cnkiLHZhbHVlcz1jb250aW5lbnRhbC5jb3VudHJ5LmNvbHMuYnJldzIkY291bnRyeS5jb2wsIGJyZWFrcz1jb250aW5lbnRhbC5jb3VudHJ5LmNvbHMuYnJldzIkR2VvX0NvdW50cnkpICsKICB0aGVtZS50ZXh0LnNpemUKZnVsbC5iZWFzdDIudHJlZS5wbG90MS5tZXRhIDwtIGZ1bGwuYmVhc3QyLnRyZWUucGxvdDEubWV0YSArIG5ld19zY2FsZV9maWxsKCkKI2JlYXN0LmNvdW50cnkubGVnZW5kIDwtIGdldF9sZWdlbmQoVFBBLmJlYXN0LnBsb3QxLm1ldGEgKyB0aGVtZShsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNjUsImxpbmUiKSxsZWdlbmQucG9zaXRpb249J3JpZ2h0JykpCgpmdWxsLmJlYXN0Mi50cmVlLnBsb3QxLm1ldGEgPC0gZ2hlYXRtYXAoZnVsbC5iZWFzdDIudHJlZS5wbG90MS5tZXRhLGRhdGEuZnJhbWUocm93Lm5hbWVzPVRQQS5tZXRhMS4yLnBpbmVjb25lJFNhbXBsZV9OYW1lLCBZZWFyPVRQQS5tZXRhMS4yLnBpbmVjb25lJFNhbXBsZV81eWVhci53aW5kb3csIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKSwgY29sb3I9TlVMTCx3aWR0aD0wLjA1LCBvZmZzZXQ9NzAsY29sbmFtZXNfYW5nbGU9MCxjb2xuYW1lc19vZmZzZXRfeT0tMS41LCBmb250LnNpemU9Mi4yNSkgKyBzY2FsZV9maWxsX21hbnVhbChuYW1lPSJZZWFyIix2YWx1ZXM9VFBBLjV5ZWFyLndpbmRvdy5icmV3Y29scyR3aW5kb3cuNXllYXIuY29sc1sxOihsZW5ndGgoVFBBLjV5ZWFyLndpbmRvdy5icmV3Y29scyR3aW5kb3cuNXllYXIuY29scyktMSldLCBicmVha3M9VFBBLjV5ZWFyLndpbmRvdy5icmV3Y29scyR3aW5kb3cuNXllYXJbMToobGVuZ3RoKFRQQS41eWVhci53aW5kb3cuYnJld2NvbHMkd2luZG93LjV5ZWFyKS0xKV0pICsKICB0aGVtZS50ZXh0LnNpemUgKyB0aGVtZShsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNTUsImxpbmUiKSwgbGVnZW5kLnBvc2l0aW9uPSJsZWZ0IikgKwogIGNvb3JkX2NhcnRlc2lhbih5PWMoLTUsNTIyKSkgKwogIE5VTEwKZnVsbC5iZWFzdDIudHJlZS5wbG90MS5tZXRhIDwtIGZ1bGwuYmVhc3QyLnRyZWUucGxvdDEubWV0YSArIG5ld19zY2FsZV9maWxsKCkKI2Z1bGwuYmVhc3QyLnRyZWUucGxvdDEubWV0YS5sZWdlbmQgPC0gZ2V0X2xlZ2VuZChmdWxsLmJlYXN0Mi50cmVlLnBsb3QxLm1ldGEgKyB0aGVtZShsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNjUsImxpbmUiKSxsZWdlbmQucG9zaXRpb249J3JpZ2h0JykpCgoKZnVsbC5iZWFzdDIudHJlZS5wbG90MS5tZXRhIDwtIGZ1bGwuYmVhc3QyLnRyZWUucGxvdDEubWV0YSArIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDIwMDAsIGNvbG9yPSdibHVlJywgYWxwaGE9MC41KQpmdWxsLmJlYXN0Mi50cmVlLnBsb3QxLm1ldGEgPC0gZnVsbC5iZWFzdDIudHJlZS5wbG90MS5tZXRhICsgYW5ub3RhdGUoInJlY3QiLHhtaW49MjAwMCx4bWF4PTIwMjAseW1pbj0tNCx5bWF4PTUyMSxhbHBoYT0wLjEsIGZpbGw9J2JsdWUnKQoKCmZ1bGwuYmVhc3QyLnRyZWUucGxvdDEubWV0YSAjKyBnZW9tX3RleHQyKGFlcyhzdWJzZXQ9IWlzVGlwLCBsYWJlbD1ub2RlKSwgaGp1c3Q9LS4zLCBzaXplPTIpCmBgYAoKClB1bGwgaW4gc2t5bGluZSBhbmFseXNpcyBmb3IgZnVsbCBiZWFzdDIgdHJlZQpgYGB7cn0Kc3VibGluZWFnZS5za3lsaW5lcy5maWxlcGF0aCA8LSBiZWFzdDIucnVucy5maWxlcGF0aAoKYmVhc3QyLmZ1bGwuc2t5bGluZSA8LSByZWFkLnRhYmxlKHBhc3RlMChiZWFzdDIucnVucy5maWxlcGF0aCxiZWFzdDIuZnVsbC5za3lsaW5lLnBhdGgpLCBzZXA9Ilx0IiwgaGVhZGVyPVQpCmJlYXN0Mi5mdWxsLmxpbmVhZ2VzIDwtIHJlYWQudGFibGUocGFzdGUwKGJlYXN0Mi5ydW5zLmZpbGVwYXRoLGJlYXN0Mi5mdWxsLmxpbmVhZ2VzLnBhdGgpLCBzZXA9Ilx0IiwgaGVhZGVyPVQpCgojIENocmlzIFJ1aXMnIHNjcmlwdCB0byBleHRyYWN0IGRpc3RyaWJ1dGlvbiBvZiB0cmVlcyBzdXBwb3J0aW5nIGV4cGFuc2lvbiBhYm92ZSBiYXNlbGluZQojIEluIHRoaXMgYW5hbHlzaXMsIGxvb2tlZCBmb3IgMi1mb2xkIGV4cGFuc2lvbiAoLXAgMTAwKSwgaW4gd2hpY2ggMC42NzQ1ICg2Ny41JSkgc3VwcG9ydGVkIGV4cGFuc2lvbgpiZWFzdDIuZnVsbC5wb3BkaXN0cm8gPC0gcmVhZC50YWJsZShwYXN0ZTAoYmVhc3QyLnJ1bnMuZmlsZXBhdGgsYmVhc3QyLmZ1bGwucG9wZGlzdHJvLnBhdGgpLCBzZXA9Ilx0IiwgaGVhZGVyPVQpCgoKIyBwbG90IHNreWxpbmUKYmVhc3QyLmZ1bGwuc2t5bGluZS5wbG90IDwtIGdncGxvdChiZWFzdDIuZnVsbC5za3lsaW5lLCBhZXMoVGltZSxNZWRpYW4pKSArIAogIGdlb21fbGluZSgpICsgZ2VvbV9yaWJib24oYWVzKHltaW49TG93ZXIsIHltYXg9VXBwZXIpLCBhbHBoYT0wLjIsIGZpbGw9J2JsYWNrJykgKwogIHRoZW1lX2xpZ2h0KCkgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoc2VxKDE3NDAsMjAyMCwyMCkpLCBleHBhbmQ9YygwLjAxLDAuMDEpKSArIAogIHNjYWxlX3lfbG9nMTAoKSArIAogIGNvb3JkX2NhcnRlc2lhbih4PWMoMTc0MCwyMDIwKSx5PWMoMzAsMzAwMCkpICsgCiAgdGhlbWUudGV4dC5zaXplICsgbGFicyh5PSJSZWxhdGl2ZSBnZW5ldGljXG5kaXZlcnNpdHkiLCB4PSJZZWFyIikgKyAKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAyMDAwLCBjb2xvcj0nYmx1ZScsIGFscGhhPTAuNSkgKwogIHRoZW1lKHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3I9J3doaXRlJywgZmlsbD0nd2hpdGUnLGxpbmV0eXBlPSJzb2xpZCIpLCBzdHJpcC50ZXh0Lnk9ZWxlbWVudF90ZXh0KGNvbG9yID0gImdyZXkyNSIsYW5nbGU9MCwgc2l6ZT0xMCkpCgoKIyBQbG90ICdsaW5lYWdlcyB0aHJvdWdoIHRpbWUnCmJlYXN0Mi5mdWxsLmxpbmVhZ2VzLnBsb3QgPC0gZ2dwbG90KGJlYXN0Mi5mdWxsLmxpbmVhZ2VzLCBhZXMoVGltZSxNZWRpYW4pKSArIAogIGdlb21fbGluZSgpICsgZ2VvbV9yaWJib24oYWVzKHltaW49TG93ZXIsIHltYXg9VXBwZXIpLCBhbHBoYT0wLjIsIGZpbGw9J2JsYWNrJykgKwogIHRoZW1lX2xpZ2h0KCkgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoc2VxKDE3NDAsMjAyMCwyMCkpLCBleHBhbmQ9YygwLjAxLDAuMDEpKSArIAogIHNjYWxlX3lfbG9nMTAoKSArIAogIGNvb3JkX2NhcnRlc2lhbih4PWMoMTc0MCwyMDIwKSx5PWMoMSwxMDAwKSkgKyAKICB0aGVtZS50ZXh0LnNpemUgKyBsYWJzKHk9IkluZmVycmVkIExpbmVhZ2VzIiwgeD0iWWVhciIpICsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMjAwMCwgY29sb3I9J2JsdWUnLCBhbHBoYT0wLjUpICsKICB0aGVtZShzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG9yPSd3aGl0ZScsIGZpbGw9J3doaXRlJyxsaW5ldHlwZT0ic29saWQiKSwgc3RyaXAudGV4dC55PWVsZW1lbnRfdGV4dChjb2xvciA9ICJncmV5MjUiLGFuZ2xlPTAsIHNpemU9MTApKQoKCiMgUGxvdCBwb3B1bGF0aW9uIGV4cGFuc2lvbiBkYXRlIGRpc3RybwpiZWFzdDIuZnVsbC5wb3BkaXN0cm9zLnN0YXJ0cyA8LSBnZ3Bsb3QoYmVhc3QyLmZ1bGwucG9wZGlzdHJvW2JlYXN0Mi5mdWxsLnBvcGRpc3RybyRJbmNyZWFzZV9kYXRlPjAsXSwgYWVzKCJGdWxsIFRyZWUiLEluY3JlYXNlX2RhdGUpKSArCiAgZ2VvbV9zaW5hKGFscGhhPTAuNzUsY29sb3I9ImdyZXk4MCIsIHNpemU9MSkgKyAKICBnZW9tX2JveHBsb3QoYWxwaGE9MC4wLG91dGxpZXIuc2hhcGUgPSBOQSwgd2lkdGg9MC4yNSkgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMTc0MCwyMDIwKSkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3M9YyhzZXEoMTc0MCwyMDIwLDIwKSksIGV4cGFuZD1jKDAuMDEsMC4wMSksIGxpbWl0cyA9IGMoMTc0MCwyMDIwKSkgKyAKICB0aGVtZV9saWdodCgpICsgCiAgY29vcmRfZmxpcCgpICsgdGhlbWUudGV4dC5zaXplICsKICB0aGVtZShzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG9yPSd3aGl0ZScsIGZpbGw9J3doaXRlJyxsaW5ldHlwZT0ic29saWQiKSwgc3RyaXAudGV4dC55PWVsZW1lbnRfdGV4dChjb2xvciA9ICJncmV5MjUiLGFuZ2xlPTAsIHNpemU9MTApKSArCiAgdGhlbWUoYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzLnk9ZWxlbWVudF9ibGFuaygpKSArCiAgbGFicyh5PSJZZWFyIiwgeD0iRGlzdHJpYnV0aW9uIGRlbnNpdHlcbihzdGFydCBvZiAyLWZvbGRcbnBvcHVsYXRpb24gZXhwYW5zaW9uKSIpICsgCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMjAwMCwgY29sb3I9J2JsdWUnLCBhbHBoYT0wLjUpICsKICBOVUxMCgojIGFsdGVybmF0ZSBwbG90IHR5cGUKYmVhc3QyLmZ1bGwucG9wZGlzdHJvcy5zdGFydHMuZGVuc2lwbG90IDwtIGdncGxvdChiZWFzdDIuZnVsbC5wb3BkaXN0cm9bYmVhc3QyLmZ1bGwucG9wZGlzdHJvJEluY3JlYXNlX2RhdGU+MCxdLCBhZXMoeD1JbmNyZWFzZV9kYXRlKSkgKyAKICBnZW9tX2RlbnNpdHkoKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW09YygxNzQwLDIwMjApKSArCiAgI3NjYWxlX3hfY29udGludW91cyhicmVha3M9YyhzZXEoMTc0MCwyMDIwLDIwKSksIGV4cGFuZD1jKDAuMDEsMC4wMSksIGxpbWl0cz1jKDE3NDAsMjAyMCkpICsgCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKHNlcSgxNzQwLDIwMjAsMjApKSwgZXhwYW5kPWMoMC4wMSwwLjAxKSkgKyAKICB0aGVtZV9saWdodCgpICsgCiAgdGhlbWUudGV4dC5zaXplICsgCiAgbGFicyh4PSJZZWFyIiwgeT0iRGlzdHJpYnV0aW9uIGRlbnNpdHlcbihzdGFydCBvZiAyLWZvbGRcbnBvcHVsYXRpb24gZXhwYW5zaW9uKSIpICsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMjAwMCwgY29sb3I9J2JsdWUnLCBhbHBoYT0wLjUpICsKICBOVUxMCiAgCgoKCiNwbG90X2dyaWQoYmVhc3QyLmZ1bGwuc2t5bGluZS5wbG90LGJlYXN0Mi5mdWxsLmxpbmVhZ2VzLnBsb3QsIG5jb2w9MSwgYWxpZ249VCkKI3Bsb3RfZ3JpZChiZWFzdDIuZnVsbC5za3lsaW5lLnBsb3QgKyB4LnRoZW1lLnN0cmlwLCBiZWFzdDIuZnVsbC5saW5lYWdlcy5wbG90ICsgeC50aGVtZS5zdHJpcCwgYmVhc3QyLmZ1bGwucG9wZGlzdHJvcy5zdGFydHMsIG5jb2w9MSwgYWxpZ249VCkKCiNwbG90cy5iZWFzdDIuZnVsbC5za3lsaW5lLmRpc3Ryby5jb21iaSA8LSBwbG90X2dyaWQoYmVhc3QyLmZ1bGwuc2t5bGluZS5wbG90ICsgeC50aGVtZS5zdHJpcCwgYmVhc3QyLmZ1bGwubGluZWFnZXMucGxvdCArIHgudGhlbWUuc3RyaXAsIGJlYXN0Mi5mdWxsLnBvcGRpc3Ryb3Muc3RhcnRzLmRlbnNpcGxvdCwgbmNvbD0xLCBhbGlnbj0ndicsYXhpcz0ndCcsIGxhYmVscyA9IGMoJ0InLCdDJywnRCcpLCBsYWJlbF9zaXplID0gMTEsICBsYWJlbF94PTAsIGxhYmVsX3k9MSwgc2NhbGU9MC45NSkKCnBsb3RzLmJlYXN0Mi5mdWxsLnNreWxpbmUuZGlzdHJvLmNvbWJpIDwtIHBsb3RfZ3JpZChiZWFzdDIuZnVsbC5za3lsaW5lLnBsb3QgKyB4LnRoZW1lLnN0cmlwLCBiZWFzdDIuZnVsbC5wb3BkaXN0cm9zLnN0YXJ0cy5kZW5zaXBsb3QsIG5jb2w9MSwgYWxpZ249J3YnLGF4aXM9J3QnLCBsYWJlbHMgPSBjKCdCJywnQycpLCBsYWJlbF9zaXplID0gMTEsICBsYWJlbF94PTAsIGxhYmVsX3k9MSwgc2NhbGU9MC45NSkKCgpwbG90cy5iZWFzdDIuZnVsbC5za3lsaW5lLmRpc3Ryby5jb21iaQpgYGAKCgoKTWFrZSBjb21iaW5lZCBwbG90IChiZWFzdDIgZnVsbCArIHNreWxpbmVzKQpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTEyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojYXJyYW5nZS5wbG90cy5iZWFzdDIuZnVsbC5za3lsaW5lLmRpc3Ryby5jb21iaSA8LSBwbG90X2dyaWQoJycscGxvdHMuYmVhc3QyLmZ1bGwuc2t5bGluZS5kaXN0cm8uY29tYmksICcnLCBuY29sPTEsIHJlbF9oZWlnaHRzPWMoMSw0LDIpKQphcnJhbmdlLnBsb3RzLmJlYXN0Mi5mdWxsLnNreWxpbmUuZGlzdHJvLmNvbWJpIDwtIHBsb3RfZ3JpZCgnJyxwbG90cy5iZWFzdDIuZnVsbC5za3lsaW5lLmRpc3Ryby5jb21iaSwgJycsIG5jb2w9MSwgcmVsX2hlaWdodHM9YygxLDQsNCkpCgoKIyBQbG90IGZ1bGwgQkVBU1QgdHJlZSB3aXRoIG1ldGFkYXRhIHN0cmlwcwpwbG90LmZ1bGwuYmVhc3QyLndpdGguc2t5bGluZS5kaXN0cm9zIDwtIHBsb3RfZ3JpZChmdWxsLmJlYXN0Mi50cmVlLnBsb3QxLm1ldGEsYXJyYW5nZS5wbG90cy5iZWFzdDIuZnVsbC5za3lsaW5lLmRpc3Ryby5jb21iaSxuY29sPTIsIHJlbF93aWR0aHM9Yyg0LDIpLCBsYWJlbHM9YygnQScsJycpLCBsYWJlbF9zaXplPTExKQoKIyBQbG90IGZ1bGwgQkVBU1QgdHJlZSB3aXRob3V0IG1ldGFkYXRhCiNwbG90LmZ1bGwuYmVhc3QyLndpdGguc2t5bGluZS5kaXN0cm9zIDwtIHBsb3RfZ3JpZChmdWxsLmJlYXN0Mi50cmVlLnBsb3QxICsgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMjAwMCwgY29sb3I9J2JsdWUnLCBhbHBoYT0wLjUpICsgYW5ub3RhdGUoInJlY3QiLHhtaW49MjAwMCx4bWF4PTIwMjAseW1pbj0tNCx5bWF4PTUyMSxhbHBoYT0wLjEsIGZpbGw9J2JsdWUnKSwgYXJyYW5nZS5wbG90cy5iZWFzdDIuZnVsbC5za3lsaW5lLmRpc3Ryby5jb21iaSxuY29sPTIsIHJlbF93aWR0aHM9Yyg0LDIpLCBsYWJlbHM9YygnQScsJycpLCBsYWJlbF9zaXplPTExKQoKCiNDYWlybzo6Q2Fpcm8oZmlsZT1wYXN0ZTAoRmlndXJlX291dHB1dF9kaXJlY3RvcnksICJGaWd1cmUzX0Z1bGwtYmVhc3QyK19za3lsaW5lLStwb3AtZXhwYW5zaW9uX18wMi0yMDIxLnN2ZyIpLCB3aWR0aCA9IDE1MDAsIGhlaWdodCA9IDEwMDAsdHlwZT0ic3ZnIix1bml0cyA9ICJwdCIpCnBsb3QuZnVsbC5iZWFzdDIud2l0aC5za3lsaW5lLmRpc3Ryb3MKI2Rldi5vZmYoKQoKCmBgYAoKCgoKCiMgTG9vayBhdCBleHBsaWNpdCBzdXBwb3J0IGZvciBwb3B1bGF0aW9uIGRlY2xpbmUgYW5kIGV4cGFuc2lvbiB3aXRoaW4gdGhlIEJlYXN0MiB0cmVlIGRpc3RyaWJ1dGlvbiBcCgpFeHRyYWN0IHRyZWVzIHN1cHBvcnRpbmcgYSBwb3B1bGF0aW9uIDItZm9sZCBkZWNsaW5lIHdpdGhpbiBhIGRlZmluZWQgd2luZG93ICgxOTkwLTIwMDUpIHVzaW5nIENocmlzIFJ1aXMnIHNjcmlwdDpcCmBweXRob24zIC9uZnMvdXNlcnMvbmZzX20vbWIyOS9zY3JpcHRzL3BvcHVsYXRpb25fY2hhbmdlX3N1cHBvcnRfQkVBU1QucHkgLXQgVFBBLXViZXJfYmVhc3QyX3N0cmljdC1za3lsaW5lLTUwME1fMTBwb3BfY29tYmluZWQudHJlZXMgLWwgVFBBLXViZXJfYmVhc3QyX3N0cmljdC1za3lsaW5lLTUwME1fMTBwb3BfY29tYmluZWQubG9nIC1wIDUwIC13IDE5OTAgMjAwNSAtLWRlY3JlYXNlIC1kIDIwMTkuNSAtYiAyIC1vIGJlYXN0Ml9zdHJpY3Qtc2t5bGluZS01MDBNXzEwcG9wX3BvcC1kZWNsaW5lLjE5OTAtMjAwNS5wNTBgIFwKXApBbmFseXNpcyBzaG93cyA4Mi44JSBvZiB0cmVlcyAoMTExOTEvICkgc3VwcG9ydCBhIHBvcHVsYXRpb24gZGVjbGluZSBiZXR3ZWVuIDE5OTAtMjAwNS4gXApcCgpFeHRyYWN0IHRyZWVzIHN1cHBvcnRpbmcgYSAyLWZvbGQgcG9wdWxhdGlvbiBpbmNyZWFzZSB3aXRoaW4gYSBkZWZpbmVkIHdpbmRvdyAoMjAwMC0yMDE1KSB1c2luZyBDaHJpcyBSdWlzJyBzY3JpcHQ6XApgcHl0aG9uMyAvbmZzL3VzZXJzL25mc19tL21iMjkvc2NyaXB0cy9wb3B1bGF0aW9uX2NoYW5nZV9zdXBwb3J0X0JFQVNULnB5IC10IFRQQS11YmVyX2JlYXN0Ml9zdHJpY3Qtc2t5bGluZS01MDBNXzEwcG9wX2NvbWJpbmVkLnRyZWVzIC1sIFRQQS11YmVyX2JlYXN0Ml9zdHJpY3Qtc2t5bGluZS01MDBNXzEwcG9wX2NvbWJpbmVkLmxvZyAtcCAxMDAgLXcgMjAwMCAyMDE1IC1kIDIwMTkuNSAtYiAyYCBcClwKQW5hbHlzaXMgc2hvd3MgODMuMyUgb2YgdHJlZXMgKDExMjQ1LyApIHN1cHBvcnQgYSBwb3B1bGF0aW9uIGluY3JlYXNlIGJldHdlZW4gMjAwMC0yMDE1LiBcCgoKVG8gYmUgY29uc2lzdGVudCB3aXRoIHRoZSAnZGVjbGluZScgcGxvdCwgZXh0cmFjdGVkIHRyZWVzIHN1cHBvcnRpbmcgYSAyLWZvbGQgcG9wdWxhdGlvbiBpbmNyZWFzZSB3aXRoaW4gYSBkZWZpbmVkIHdpbmRvdyAoMTk5MC0yMDE1KSB1c2luZyBDaHJpcyBSdWlzJyBzY3JpcHQ6XApgcHl0aG9uMyAvbmZzL3VzZXJzL25mc19tL21iMjkvc2NyaXB0cy9wb3B1bGF0aW9uX2NoYW5nZV9zdXBwb3J0X0JFQVNULnB5IC10IFRQQS11YmVyX2JlYXN0Ml9zdHJpY3Qtc2t5bGluZS01MDBNXzEwcG9wX2NvbWJpbmVkLnRyZWVzIC1sIFRQQS11YmVyX2JlYXN0Ml9zdHJpY3Qtc2t5bGluZS01MDBNXzEwcG9wX2NvbWJpbmVkLmxvZyAtcCAxMDAgLXcgMTk5MCAyMDE1IC1kIDIwMTkuNSAtYiAyYCBcClwKQW5hbHlzaXMgc2hvd3MgNTguNSUgb2YgdHJlZXMgKDExMjQ1LyApIHN1cHBvcnQgYSBwb3B1bGF0aW9uIGluY3JlYXNlIGJldHdlZW4gMTk5MC0yMDE1LiBcClwKXApQbG90IGRpc3RyaWJ1dGlvbnMKCmBgYHtyfQpiZWFzdDIucG9wLmRlY2xpbmUgPC0gcmVhZC5jc3YoYmVhc3QyLnBvcC5kZWNsaW5lLmZpbGUsIGhlYWRlcj1ULCBzdHJpbmdzQXNGYWN0b3JzPUYpCmJlYXN0Mi5wb3AuaW5jcmVhc2UgPC0gcmVhZC5jc3YoYmVhc3QyLnBvcC5pbmNyZWFzZS5maWxlLCBoZWFkZXI9VCwgc3RyaW5nc0FzRmFjdG9ycz1GKQoKYmVhc3QyLnBvcC5kZWNsaW5lJHF1ZXJ5IDwtICJEZWNsaW5lIgpiZWFzdDIucG9wLmluY3JlYXNlJHF1ZXJ5IDwtICJFeHBhbnNpb24iCmJlYXN0Mi5wb3AuZGVjbGluZS5pbmNyZWFzZSA8LSByYmluZChiZWFzdDIucG9wLmRlY2xpbmUsYmVhc3QyLnBvcC5pbmNyZWFzZSkKCiMgQ3JlYXRlIGRhdGFmcmFtZSB3aXRoIHN1cHBvcnRpbmcgdmFsdWVzIGZvciB0ZXh0IHBsb3R0aW5nCiNkZWNsaW5lLnN1cHBvcnQudmFsdWUgPC0gODIuOAojaW5jcmVhc2Uuc3VwcG9ydC52YWx1ZSA8LSA4My4zCmRlY2xpbmUuc3VwcG9ydC52YWx1ZSA8LSAiOTAuNyIKaW5jcmVhc2Uuc3VwcG9ydC52YWx1ZSA8LSAiNTkuMCIKCgoKYmVhc3QuZGVjbGluZS5pbmNyZWFzZS5zdXBwb3J0LnZhbHVlcyA8LSBkYXRhLmZyYW1lKHF1ZXJ5PWMoIkRlY2xpbmUiLCJFeHBhbnNpb24iKSxwcm9wb3J0aW9uPWMoZGVjbGluZS5zdXBwb3J0LnZhbHVlLGluY3JlYXNlLnN1cHBvcnQudmFsdWUpLCBtZWRpYW4uZGF0ZT1jKG1lZGlhbihiZWFzdDIucG9wLmRlY2xpbmUkRGF0ZV9vZl9jaGFuZ2UpLCBtZWRpYW4oYmVhc3QyLnBvcC5pbmNyZWFzZSREYXRlX29mX2NoYW5nZSkpLCBzdHJpbmdzQXNGYWN0b3JzPUYpCgoKcC5iZWFzdDIuZnVsbC5wb3BkZWNsaW5lLmluY3JlYXNlLmRlbnNpcGxvdCA8LSBnZ3Bsb3QoYmVhc3QyLnBvcC5kZWNsaW5lLmluY3JlYXNlLCBhZXMoeD1EYXRlX29mX2NoYW5nZSwgZ3JvdXA9cXVlcnksIGNvbG9yPXF1ZXJ5LCBmaWxsPXF1ZXJ5KSkgKyAKICBnZW9tX2RlbnNpdHkoYWxwaGE9MC4yNSkgKwogIHNjYWxlX3hfY29udGludW91cyhleHBhbmQ9YygwLjAxLDAuMDEpKSArIAogIHRoZW1lX2xpZ2h0KCkgKyAKICB0aGVtZS50ZXh0LnNpemUgKyAKICBsYWJzKHg9IlllYXIiLCB5PSJQb3N0ZXJpb3IgZGlzdHJpYnV0aW9uIGRlbnNpdHlcbihzdGFydCBvZiAyLWZvbGQgcG9wdWxhdGlvbiBkZWNsaW5lL2V4cGFuc2lvbikiLCBjb2xvcj0iS2V5IikgKyAKICBndWlkZXMoZmlsbD1GQUxTRSkgKwogIGdlb21fdGV4dChkYXRhPWJlYXN0LmRlY2xpbmUuaW5jcmVhc2Uuc3VwcG9ydC52YWx1ZXMsIGFlcyh4PW1lZGlhbi5kYXRlLCB5PTAuNDUsIGxhYmVsPXBhc3RlMChwcm9wb3J0aW9uLCIlIG9mIHN1cHBvcnRpbmcgdHJlZXMiKSksc2l6ZT0zKSArIAogIGdlb21fdGV4dChkYXRhPWJlYXN0LmRlY2xpbmUuaW5jcmVhc2Uuc3VwcG9ydC52YWx1ZXMsIGFlcyh4PW1lZGlhbi5kYXRlLCB5PTAuNSwgbGFiZWw9cGFzdGUwKCJtZWRpYW4gZGF0ZTogIixyb3VuZChtZWRpYW4uZGF0ZSwxKSkpLHNpemU9MykgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAndG9wJykgCiAgI2dlb21fdmxpbmUoZGF0YT1iZWFzdC5kZWNsaW5lLmluY3JlYXNlLnN1cHBvcnQudmFsdWVzLCBhZXMoeGludGVyY2VwdD1tZWRpYW4uZGF0ZSwgY29sb3I9cXVlcnkpKSArCiAgTlVMTAoKCgojQ2Fpcm86OkNhaXJvKGZpbGU9cGFzdGUwKEZpZ3VyZV9vdXRwdXRfZGlyZWN0b3J5LCAiU3VwcGxlbWVudGFyeV9GaWd1cmU4X19Ta3lsaW5lLXBvcC1kZWNsaW5lK2V4cGFuc2lvbi1kYXRlc19fMDItMjAyMS5zdmciKSwgd2lkdGggPSA0NTAsIGhlaWdodCA9IDMwMCx0eXBlPSJzdmciLHVuaXRzID0gInB0IikgIApwLmJlYXN0Mi5mdWxsLnBvcGRlY2xpbmUuaW5jcmVhc2UuZGVuc2lwbG90CiNkZXYub2ZmKCkKCgoKYGBgCgpMb29rIGF0IHRyZWVzIHN1cHBvcnRpbmcgb3Igbm90LXN1cHBvcnRpbmcgZXhwYW5zaW9uCmBgYHtyfQpwb3AuZGVjbGluZS5zdXBwb3J0aW5nLnRyZWVzIDwtIHJlYWQubmV4dXMocG9wLmRlY2xpbmUuc3VwcG9ydGluZy50cmVlcy5maWxlKQpwb3AuZGVjbGluZS5zdXBwb3J0aW5nLnRyZWVzLnNhbXBsZTI1IDwtc2FtcGxlKHBvcC5kZWNsaW5lLnN1cHBvcnRpbmcudHJlZXMsc2l6ZT0yNSkKCnBvcC5kZWNsaW5lLm5vdHN1cHBvcnRpbmcudHJlZXMgPC0gcmVhZC5uZXh1cyhwb3AuZGVjbGluZS5ub3RzdXBwb3J0aW5nLnRyZWVzLmZpbGUpCnBvcC5kZWNsaW5lLm5vdHN1cHBvcnRpbmcudHJlZXMuc2FtcGxlMjUgPC1zYW1wbGUocG9wLmRlY2xpbmUubm90c3VwcG9ydGluZy50cmVlcyxzaXplPTI1KQoKVFBBLm1ldGExLjIucGluZWNvbmUkU2FtcGxlX05hbWUuZGF0ZXMgPC0gcGFzdGUwKFRQQS5tZXRhMS4yLnBpbmVjb25lJFNhbXBsZV9OYW1lLCJ8IixUUEEubWV0YTEuMi5waW5lY29uZSRTYW1wbGVfWWVhcikKCgpwLnBvcC5kZWNsaW5lLm5vdHN1cHBvcnRpbmcudHJlZXMuc2FtcGxlMjUgPC0gZ2dkZW5zaXRyZWUocG9wLmRlY2xpbmUubm90c3VwcG9ydGluZy50cmVlcy5zYW1wbGUyNSwgYWxwaGE9MC4xLG1yc2Q9IjIwMTktMDYtMDEiKSArIAogIHRoZW1lX3RyZWUyKCkKcC5wb3AuZGVjbGluZS5ub3RzdXBwb3J0aW5nLnRyZWVzLnNhbXBsZTI1IDwtIHAucG9wLmRlY2xpbmUubm90c3VwcG9ydGluZy50cmVlcy5zYW1wbGUyNSAlPCslIGRhdGEuZnJhbWUoU2FtcGxlX05hbWU9VFBBLm1ldGExLjIucGluZWNvbmUkU2FtcGxlX05hbWUuZGF0ZXMsIFN1YmxpbmVhZ2U9VFBBLm1ldGExLjIucGluZWNvbmUkVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UpICsgCiAgZ2VvbV90aXBwb2ludChhZXMoY29sb3I9U3VibGluZWFnZSksIHNpemU9MSwgYWxwaGE9MC41KSArIAogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lPSJTdWJsaW5lYWdlIix2YWx1ZXM9c3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2UuY29scywgYnJlYWtzPXN1YmxpbmVhZ2VzLmNvbHMuYnJldyRzdWJsaW5lYWdlKSArCiAgIyBBZGQgZGF0ZSBsaW5lcyBmb3IgZWFzeSBpbnRlcnByZXRhdGlvbiAgCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDEzMDAsMTQwMCwxNTAwLDE2MDAsMTcwMCwxODAwLDE4NTAsMTkwMCwxOTI1LDE5NTAsMTk3NSwyMDAwLDIwMjApLCBtaW5vcl9icmVha3M9c2VxKDE5NTAsIDIwMjAsIDUpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciAgID0gZWxlbWVudF9saW5lKGNvbG9yPSJncmV5NTAiLCBzaXplPS4yKSwKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yICAgPSBlbGVtZW50X2xpbmUoY29sb3I9ImdyZXk4NSIsIHNpemU9LjIpLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yLnkgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgZ2d0aXRsZSgiVHJlZXMgbm90IHN1cHBvcnRpbmcgcG9wdWxhdGlvbiBleHBhbnNpb24iKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSkpCiNwLnBvcC5kZWNsaW5lLm5vdHN1cHBvcnRpbmcudHJlZXMuc2FtcGxlMjUKCgpwLnBvcC5kZWNsaW5lLnN1cHBvcnRpbmcudHJlZXMuc2FtcGxlMjUgPC0gZ2dkZW5zaXRyZWUocG9wLmRlY2xpbmUuc3VwcG9ydGluZy50cmVlcy5zYW1wbGUyNSwgYWxwaGE9MC4xLG1yc2Q9IjIwMTktMDYtMDEiKSArIAogIHRoZW1lX3RyZWUyKCkKcC5wb3AuZGVjbGluZS5zdXBwb3J0aW5nLnRyZWVzLnNhbXBsZTI1IDwtIHAucG9wLmRlY2xpbmUuc3VwcG9ydGluZy50cmVlcy5zYW1wbGUyNSAlPCslIGRhdGEuZnJhbWUoU2FtcGxlX05hbWU9VFBBLm1ldGExLjIucGluZWNvbmUkU2FtcGxlX05hbWUuZGF0ZXMsIFN1YmxpbmVhZ2U9VFBBLm1ldGExLjIucGluZWNvbmUkVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UpICsgCiAgZ2VvbV90aXBwb2ludChhZXMoY29sb3I9U3VibGluZWFnZSksIHNpemU9MSwgYWxwaGE9MC41KSArIAogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lPSJTdWJsaW5lYWdlIix2YWx1ZXM9c3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2UuY29scywgYnJlYWtzPXN1YmxpbmVhZ2VzLmNvbHMuYnJldyRzdWJsaW5lYWdlKSArCiAgIyBBZGQgZGF0ZSBsaW5lcyBmb3IgZWFzeSBpbnRlcnByZXRhdGlvbiAgCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDEzMDAsMTQwMCwxNTAwLDE2MDAsMTcwMCwxODAwLDE4NTAsMTkwMCwxOTI1LDE5NTAsMTk3NSwyMDAwLDIwMjApLCBtaW5vcl9icmVha3M9c2VxKDE5NTAsIDIwMjAsIDUpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciAgID0gZWxlbWVudF9saW5lKGNvbG9yPSJncmV5NTAiLCBzaXplPS4yKSwKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yICAgPSBlbGVtZW50X2xpbmUoY29sb3I9ImdyZXk4NSIsIHNpemU9LjIpLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yLnkgPSBlbGVtZW50X2JsYW5rKCkpICsKICBnZ3RpdGxlKCJUcmVlcyBzdXBwb3J0aW5nIHBvcHVsYXRpb24gZXhwYW5zaW9uIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpKQojcC5wb3AuZGVjbGluZS5zdXBwb3J0aW5nLnRyZWVzLnNhbXBsZTI1CgoKCnBsb3RfZ3JpZChwLnBvcC5kZWNsaW5lLnN1cHBvcnRpbmcudHJlZXMuc2FtcGxlMjUsIHAucG9wLmRlY2xpbmUubm90c3VwcG9ydGluZy50cmVlcy5zYW1wbGUyNSwgbmNvbD0xKQpgYGAKVGhlcmUgYXJlIG5vIG9idmlvdXMgZGlmZmVyZW5jZXMgaW4gdHJlZSB0b3BvbG9neSBoZXJlLiBJdCBpcyBsaWtlbHkgdGhhdCB0aGVzZSB0cmVlcyBlaXRoZXIgc2hvdyBleHBhbnNpb24gPDItZm9sZCwgb3IgdGhlIGJhc2VsaW5lIHVzZWQgdG8gYXZlcmFnZSBpcyBhZmZlY3RpbmcgZXhwYW5zaW9uIC0gZS5nLiBpZiB0aGUgYmFzZWxpbmUgd2FzIGhpZ2hlciBhdCB0aGUgc3RhcnQgb2YgdGhlIGRlY2xpbmUsIGV4cGFuc2lvbiB3b3VsZCBub3QgYmUgZGV0ZWN0ZWQuIAoKCgoKXApFeHRyYWN0IGluZGl2aWR1YWwgc3VibGluZWFnZXMgZm9yIEJheWVzaWFuIFNreWxpbmUgYW5hbHlzaXMgKG9ubHkgdGFrZSBzdWJsaW5lYWdlcyBvZiBkZWNlbnQgc2l6ZSwgd2l0aCBubyBvdXRncm91cHMpXAoKYGBge3J9Cm1ham9yLm11bHRpY291bnRyeS5zdWJsaW5lYWdlcyA8LSBzdWJsaW5lYWdlLmNvdW50c1tzdWJsaW5lYWdlLmNvdW50cyRDb3VudD4xMCxdCm1ham9yLm11bHRpY291bnRyeS5zdWJsaW5lYWdlcwpzdWJsaW5lYWdlLjEubWV0YSA8LSBUUEEubWV0YTEuMi5waW5lY29uZVtUUEEubWV0YTEuMi5waW5lY29uZSRUUEEucGluZWNvbmUuc3VibGluZWFnZT09MSxjKCJDbGVhbmVkX2Zhc3RxX2lkIiwiU2FtcGxlX05hbWUiLCJTYW1wbGVfWWVhciIpXQpzdWJsaW5lYWdlLjIubWV0YSA8LSBUUEEubWV0YTEuMi5waW5lY29uZVtUUEEubWV0YTEuMi5waW5lY29uZSRUUEEucGluZWNvbmUuc3VibGluZWFnZT09MixjKCJDbGVhbmVkX2Zhc3RxX2lkIiwiU2FtcGxlX05hbWUiLCJTYW1wbGVfWWVhciIpXQojc3VibGluZWFnZS40Lm1ldGEgPC0gVFBBLm1ldGExLjIucGluZWNvbmVbVFBBLm1ldGExLjIucGluZWNvbmUkVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2U9PTQsYygiQ2xlYW5lZF9mYXN0cV9pZCIsIlNhbXBsZV9OYW1lIiwiU2FtcGxlX1llYXIiKV0Kc3VibGluZWFnZS44Lm1ldGEgPC0gVFBBLm1ldGExLjIucGluZWNvbmVbVFBBLm1ldGExLjIucGluZWNvbmUkVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2U9PTgsYygiQ2xlYW5lZF9mYXN0cV9pZCIsIlNhbXBsZV9OYW1lIiwiU2FtcGxlX1llYXIiKV0Kc3VibGluZWFnZS4xNC5tZXRhIDwtIFRQQS5tZXRhMS4yLnBpbmVjb25lW1RQQS5tZXRhMS4yLnBpbmVjb25lJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlPT0xNCxjKCJDbGVhbmVkX2Zhc3RxX2lkIiwiU2FtcGxlX05hbWUiLCJTYW1wbGVfWWVhciIpXQoKYWxsLnBpbmVjb25lLm1ldGEgPC0gVFBBLm1ldGExLjIucGluZWNvbmUuaGF2ZWRhdGVzWyxjKCJDbGVhbmVkX2Zhc3RxX2lkIiwiU2FtcGxlX05hbWUiLCJTYW1wbGVfWWVhciIpXQpgYGAKCgpDaGVjayB0ZW1wb3JhbCBzaWduYWwgYnkgZXh0cmFjdGluZyBzdWJ0cmVlcwpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTEyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKcC5zdWJsaW4uMS5yMnQgPC0gcGxvdC5zdWJ0cmVlLlIyVChUUEEuTUx0cmVlLHN1YmxpbmVhZ2UuMS5tZXRhJFNhbXBsZV9OYW1lLFRQQS5tZXRhMS4yLnBpbmVjb25lLmhhdmVkYXRlc1ssYygiU2FtcGxlX05hbWUiLCJTYW1wbGVfWWVhciIpXSkKcC5zdWJsaW4uMi5yMnQgPC0gcGxvdC5zdWJ0cmVlLlIyVChUUEEuTUx0cmVlLHN1YmxpbmVhZ2UuMi5tZXRhJFNhbXBsZV9OYW1lLFRQQS5tZXRhMS4yLnBpbmVjb25lLmhhdmVkYXRlc1ssYygiU2FtcGxlX05hbWUiLCJTYW1wbGVfWWVhciIpXSkKcC5zdWJsaW4uOC5yMnQgPC0gcGxvdC5zdWJ0cmVlLlIyVChUUEEuTUx0cmVlLHN1YmxpbmVhZ2UuOC5tZXRhJFNhbXBsZV9OYW1lLFRQQS5tZXRhMS4yLnBpbmVjb25lLmhhdmVkYXRlc1ssYygiU2FtcGxlX05hbWUiLCJTYW1wbGVfWWVhciIpXSkKcC5zdWJsaW4uMTQucjJ0IDwtIHBsb3Quc3VidHJlZS5SMlQoVFBBLk1MdHJlZSxzdWJsaW5lYWdlLjE0Lm1ldGEkU2FtcGxlX05hbWUsVFBBLm1ldGExLjIucGluZWNvbmUuaGF2ZWRhdGVzWyxjKCJTYW1wbGVfTmFtZSIsIlNhbXBsZV9ZZWFyIildKQoKCgojQ2Fpcm86OkNhaXJvKGZpbGU9cGFzdGUwKEZpZ3VyZV9vdXRwdXRfZGlyZWN0b3J5LCAiU3VwcGxlbWVudGFyeV9GaWd1cmUxMF9TdWJsaW5lYWdlc190cmVlcytyb290MnRpcF9fMDItMjAyMS5zdmciKSwgd2lkdGggPSAxMDAwLCBoZWlnaHQgPSAxMDAwLHR5cGU9InN2ZyIsdW5pdHMgPSAicHQiKQpwbG90X2dyaWQocC5zdWJsaW4uMS5yMnQscC5zdWJsaW4uMi5yMnQscC5zdWJsaW4uOC5yMnQscC5zdWJsaW4uMTQucjJ0LG5jb2w9MiwgbGFiZWxzPWMoJ1N1YmxpbmVhZ2UgMScsJ1N1YmxpbmVhZ2UgMicsJ1N1YmxpbmVhZ2UgOCcsJ1N1YmxpbmVhZ2UgMTQnKSxzY2FsZSA9IDAuODUsbGFiZWxfc2l6ZT0xMikKI2Rldi5vZmYoKQoKYGBgCgojIEV2YWx1YXRlIHN1YnRyZWUgc2t5bGluZSBhbmFseXNlcyBcCgpTdWJsaW5lYWdlIDEgKG5ldylcClNlcXMgMzY1LCBzaXRlcyAyNzgsIHNwYW4gMTk4MS0yMDE5XAotIEdvb2QgY29udmVyZ2VuY2UgaW4gYWxsIHRyYWNlcywgc3Ryb25nIEVTUyBmb3IgbW9zdCB2YXJpYWJsZXMsIGJ1dCBsb3dlciBmb3IgYSBmZXcgb2YgdGhlIHNreWxpbmUgZ3JvdXBzIChFU1M+MTAwLCBhcGFydCBmcm9tIFNreWxpbmUuR3JvdXBzaXplMTAgd2l0aCBFU1MgNzkpIFwKLSBjbG9jayByYXRlIDEuMzRlLTcgIFwKClN1YmxpbmVhZ2UgMiAobmV3KVwKU2VxcyAzMiwgc2l0ZXMgMzYsIHNwYW4gMjAwMC0yMDE5XAotIEdvb2QgY29udmVyZ2VuY2UgaW4gYWxsIHRyYWNlcywgdmVyeSBzdHJvbmcgRVNTIGluIGFsbCBjYXNlc1wKLSBTa3lsaW5lIHN0cm9uZyBleHBhbmRpbmcgc2t5bGluZSBwbG90IFwKLSBjbG9jayByYXRlIDEuNTdlLTcgIFwKClN1YmxpbmVhZ2UgOCAobmV3KVwKU2VxcyAxNSwgc2l0ZXMgMzEsIHNwYW4gMTk4Ni0yMDE5XAotIEdvb2QgY29udmVyZ2VuY2UgaW4gYWxsIHRyYWNlcywgdmVyeSBzdHJvbmcgRVNTIGluIGFsbCBjYXNlc1wKLSBTa3lsaW5lIC0gZ29vZCBza3lsaW5lLCBzaG93aW5nIHBvc3NpYmxlIGV4cGFuc2lvbiBkdXJpbmcgOTBzLCBwb3NzaWJsZSBjb250cmFjdGlvbiBpbiAyMDEwcykgXAotIGNsb2NrIHJhdGUgMS44MGUtNyAgXAoKU3VibGluZWFnZSAxNCAobmV3KVwKU2VxcyA1NSwgc2l0ZXMgMjMsIHNwYW4gMjAxMy0yMDE5XAotIGRpZCBub3QgY29udmVyZ2UgKGF0IGFsbCkgXAotIE5vIHRlbXBvcmFsIHNpZ25hbCAoaW4gcjJ0IHBsb3RzKSBcClwKXAoKClwKXAoKCkRlZmluZSBzb21lIGZ1bmN0aW9ucyB0byBwbG90CmBgYHtyfQoKCnBsb3Quc2t5bGluZS5kYXRhIDwtIGZ1bmN0aW9uKHNreWxpbmUuZmlsZSxsaW5lYWdlcy5maWxlKXsgIAogIHNreWxpbmUuZGF0YSA8LSByZWFkLnRhYmxlKHBhc3RlMChzdWJsaW5lYWdlLnNreWxpbmVzLmZpbGVwYXRoLHNreWxpbmUuZmlsZSksIGhlYWRlcj1ULCBzZXA9Ilx0IiwgY29tbWVudC5jaGFyPSIiLHN0cmluZ3NBc0ZhY3RvcnM9RikKICBza3lsaW5lLnBsb3QgPC0gZ2dwbG90KHNreWxpbmUuZGF0YSwgYWVzKFRpbWUsTWVkaWFuKSkgKyAKICAgIGdlb21fbGluZSgpICsgZ2VvbV9yaWJib24oYWVzKHltaW49TG93ZXIsIHltYXg9VXBwZXIpLCBhbHBoYT0wLjIsIGZpbGw9J2JsYWNrJykgKwogICAgdGhlbWVfbGlnaHQoKSArIAogICAgI3NjYWxlX3hfY29udGludW91cyhicmVha3M9YyhzZXEoMTc0MCwyMDIwLDIwKSksIGV4cGFuZD1jKDAuMDEsMC4wMSkpICsgCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoc2VxKDE5ODAsMjAyMCwyMCkpLCBleHBhbmQ9YygwLjAxLDAuMDEpKSArIAogICAgc2NhbGVfeV9sb2cxMCgpICsgCiAgICBjb29yZF9jYXJ0ZXNpYW4oeD1jKDE5ODAsMjAyMCkpICsgCiAgICB0aGVtZS50ZXh0LnNpemUgKyBsYWJzKHk9IlJlbGF0aXZlIGdlbmV0aWMgZGl2ZXJzaXR5IiwgeD0iWWVhciIpICsgCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAyMDAwLCBjb2xvcj0nYmx1ZScsIGFscGhhPTAuNSkgKyBhbm5vdGF0ZSgicmVjdCIseG1pbj0yMDAwLHhtYXg9MjAyMCx5bWluPTAseW1heD0xMDAwMCxhbHBoYT0wLjEsIGZpbGw9J2JsdWUnKQogIAogICMgTGluZWFnZXMKICBza3lsaW5lLmxpbmVhZ2VzIDwtIHJlYWQudGFibGUocGFzdGUwKHN1YmxpbmVhZ2Uuc2t5bGluZXMuZmlsZXBhdGgsbGluZWFnZXMuZmlsZSksIGhlYWRlcj1ULCBzZXA9Ilx0IiwgY29tbWVudC5jaGFyPSIiLHN0cmluZ3NBc0ZhY3RvcnM9RikKICBsaW5lYWdlcy5wbG90ICA8LSBnZ3Bsb3Qoc2t5bGluZS5saW5lYWdlcywgYWVzKFRpbWUsTWVkaWFuKSkgKyAKICAgIGdlb21fbGluZSgpICsgZ2VvbV9yaWJib24oYWVzKHltaW49TG93ZXIsIHltYXg9VXBwZXIpLCBhbHBoYT0wLjIsIGZpbGw9J2JsYWNrJykgKwogICAgdGhlbWVfbGlnaHQoKSArIAogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKHNlcSgxOTgwLDIwMjAsMjApKSwgZXhwYW5kPWMoMC4wMSwwLjAxKSkgKyAKICAgICNzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoc2VxKDE3NDAsMjAyMCwyMCkpLCBleHBhbmQ9YygwLjAxLDAuMDEpKSArIAogICAgc2NhbGVfeV9sb2cxMCgpICsgCiAgICBjb29yZF9jYXJ0ZXNpYW4oeD1jKDE5ODAsMjAyMCksIHk9YygxLDMwMCkpICsgCiAgICAjc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKHNlcSgxNzQwLDIwMjAsMjApKSwgZXhwYW5kPWMoMC4wMSwwLjAxKSkgKyAKICAgIHRoZW1lLnRleHQuc2l6ZSArIGxhYnMoeT0iTGluZWFnZXMiLCB4PSJZZWFyIikgKyAKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDIwMDAsIGNvbG9yPSdibHVlJywgYWxwaGE9MC41KSArIGFubm90YXRlKCJyZWN0Iix4bWluPTIwMDAseG1heD0yMDIwLHltaW49MCx5bWF4PTUwMCxhbHBoYT0wLjEsIGZpbGw9J2JsdWUnKQogIAogIHNreWxpbmUuY29tYmluZWQucGxvdCA8LSBwbG90X2dyaWQoc2t5bGluZS5wbG90LGxpbmVhZ2VzLnBsb3QsIG5jb2w9MSwgYWxpZ249VCkKICByZXR1cm4oc2t5bGluZS5jb21iaW5lZC5wbG90KQogICNyZXR1cm4oc2t5bGluZS5wbG90KQp9CgoKYGBgCgoKIyBQbG90IHN1YmxpbmVhZ2Ugc2t5bGluZXMgd2l0aCBsaW5lYWdlcyB0aHJvdWdoIHRpbWUgLSBhbGwgdG9nZXRoZXIKYGBge3IsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTgsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpzdWJsaW5lYWdlLnNreWxpbmVzLmZpbGVwYXRoIDwtICIvVXNlcnMvbWIyOS9UcmVwb25lbWEvRXhwYW5kZWRfR2xvYmFsX1NlcXVlbmNpbmcvQW5hbHlzaXMvR2xvYmFsX1RQQV91YmVyLWFuYWx5c2lzXzIwMjBfdjIvcGh5bG8vZ29vZF9jb3ZfZGF0YXNldC9ndWJiaW5zXzIuNC4xX18yMC0xMS0xMC9iZWFzdC9pbmRpdmlkdWFsX3N1YmxpbmVhZ2VzX3JlY2xhc3NpZmllZF9fMjAyMS0wMi0wNC9iZWF1dGkvb3V0cHV0cy8iCiAgCmNvbGxlY3RlZC5za3lsaW5lcyA8LSBOVUxMCmZvciAoc3VibGluZWFnZSBpbiBjKDEsMiw4KSkgewogIHN1YmxpbmVhZ2Uuc2t5bGluZSA8LSByZWFkLnRhYmxlKHBhc3RlMChzdWJsaW5lYWdlLnNreWxpbmVzLmZpbGVwYXRoLCJUUEEtdWJlci5yZW1hc2tlZC4yMDIwLTExLTEwLmdvb2Rjb3YyNS5ndWJiaW5zLldHUy5zdWJsaW5lYWdlLm5ldy4iLHN1YmxpbmVhZ2UsIi5ub2ludi5TdHJpY3QtU2t5bGluZV9jb21iaW5lZC5za3lsaW5lLWRhdGEudHN2IiksIGhlYWRlcj1ULCBzZXA9Ilx0IiwgY29tbWVudC5jaGFyPSIiLHN0cmluZ3NBc0ZhY3RvcnM9RikKICBzdWJsaW5lYWdlLnNreWxpbmUkc3VibGluZWFnZSA8LSBzdWJsaW5lYWdlIAogIGNvbGxlY3RlZC5za3lsaW5lcyA8LSByYmluZChjb2xsZWN0ZWQuc2t5bGluZXMsIHN1YmxpbmVhZ2Uuc2t5bGluZSkKfQpiZWFzdDIuZnVsbC5za3lsaW5lJHN1YmxpbmVhZ2UgPC0gIkFsbCIKY29sbGVjdGVkLnNreWxpbmVzLmluYy5mdWxsIDwtIHJiaW5kKGNvbGxlY3RlZC5za3lsaW5lcywgYmVhc3QyLmZ1bGwuc2t5bGluZSkKY29sbGVjdGVkLnNreWxpbmVzLmluYy5mdWxsJHN1YmxpbmVhZ2UgPC0gZmFjdG9yKGNvbGxlY3RlZC5za3lsaW5lcy5pbmMuZnVsbCRzdWJsaW5lYWdlLCBsZXZlbHM9dW5pcXVlKGNvbGxlY3RlZC5za3lsaW5lcy5pbmMuZnVsbCRzdWJsaW5lYWdlKSkKCnN1YmxpbmVhZ2Uuc2t5bGluZS5jb21iaS5wbG90IDwtIGdncGxvdChjb2xsZWN0ZWQuc2t5bGluZXMuaW5jLmZ1bGwsIGFlcyhUaW1lLE1lZGlhbikpICsgCiAgZ2VvbV9saW5lKCkgKyBnZW9tX3JpYmJvbihhZXMoeW1pbj1Mb3dlciwgeW1heD1VcHBlciksIGFscGhhPTAuMiwgZmlsbD0nYmxhY2snKSArCiAgdGhlbWVfbGlnaHQoKSArIAogICNzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoc2VxKDE3NDAsMjAyMCwyMCkpLCBleHBhbmQ9YygwLjAxLDAuMDEpKSArIAogIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YyhzZXEoMTc0MCwyMDIwLDIwKSksIGV4cGFuZD1jKDAuMDEsMC4wMSkpICsgCiAgc2NhbGVfeV9sb2cxMCgpICsgCiAgY29vcmRfY2FydGVzaWFuKHg9YygxOTAwLDIwMjApLHk9YygxLDMwMDApKSArIAogIHRoZW1lLnRleHQuc2l6ZSArIGxhYnMoeT0iUmVsYXRpdmUgZ2VuZXRpYyBkaXZlcnNpdHkgKHBlciBzdWJsaW5lYWdlKSIsIHg9IlllYXIiKSArIAogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDIwMDAsIGNvbG9yPSdibHVlJywgYWxwaGE9MC41KSArICNhbm5vdGF0ZSgicmVjdCIseG1pbj0yMDAwLHhtYXg9MjAyMCx5bWluPTAseW1heD0xMDAwMCxhbHBoYT0wLjEsIGZpbGw9J2JsdWUnKSArIAogIGZhY2V0X2dyaWQoc3VibGluZWFnZX4uKSArCiAgdGhlbWUoc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvcj0nd2hpdGUnLCBmaWxsPSd3aGl0ZScsbGluZXR5cGU9InNvbGlkIiksIHN0cmlwLnRleHQueT1lbGVtZW50X3RleHQoY29sb3IgPSAiZ3JleTI1IixhbmdsZT0wLCBzaXplPTEwKSkKCgojIERvIHNhbWUgZm9yICdsaW5lYWdlcyB0aHJvdWdoIHRpbWUnCmNvbGxlY3RlZC5za3lsaW5lcy5saW5lYWdlcyA8LSBOVUxMCmZvciAoc3VibGluZWFnZSBpbiBjKDEsMiw4KSkgewogIHN1YmxpbmVhZ2Uuc2t5bGluZS5saW5lYWdlcyA8LSByZWFkLnRhYmxlKHBhc3RlMChzdWJsaW5lYWdlLnNreWxpbmVzLmZpbGVwYXRoLCJUUEEtdWJlci5yZW1hc2tlZC4yMDIwLTExLTEwLmdvb2Rjb3YyNS5ndWJiaW5zLldHUy5zdWJsaW5lYWdlLm5ldy4iLHN1YmxpbmVhZ2UsIi5ub2ludi5TdHJpY3QtU2t5bGluZV9jb21iaW5lZC5saW5lYWdlcy1kYXRhLnRzdiIpLCBoZWFkZXI9VCwgc2VwPSJcdCIsIGNvbW1lbnQuY2hhcj0iIixzdHJpbmdzQXNGYWN0b3JzPUYpCiAgc3VibGluZWFnZS5za3lsaW5lLmxpbmVhZ2VzJHN1YmxpbmVhZ2UgPC0gc3VibGluZWFnZSAKICBjb2xsZWN0ZWQuc2t5bGluZXMubGluZWFnZXMgPC0gcmJpbmQoY29sbGVjdGVkLnNreWxpbmVzLmxpbmVhZ2VzLCBzdWJsaW5lYWdlLnNreWxpbmUubGluZWFnZXMpCn0KYmVhc3QyLmZ1bGwubGluZWFnZXMkc3VibGluZWFnZSA8LSAiQWxsIgpjb2xsZWN0ZWQuc2t5bGluZXMubGluZWFnZXMuaW5jLmZ1bGwgPC0gcmJpbmQoY29sbGVjdGVkLnNreWxpbmVzLmxpbmVhZ2VzLCBiZWFzdDIuZnVsbC5saW5lYWdlcykKY29sbGVjdGVkLnNreWxpbmVzLmxpbmVhZ2VzLmluYy5mdWxsJHN1YmxpbmVhZ2UgPC0gZmFjdG9yKGNvbGxlY3RlZC5za3lsaW5lcy5saW5lYWdlcy5pbmMuZnVsbCRzdWJsaW5lYWdlLCBsZXZlbHM9dW5pcXVlKGNvbGxlY3RlZC5za3lsaW5lcy5saW5lYWdlcy5pbmMuZnVsbCRzdWJsaW5lYWdlKSkKCgpzdWJsaW5lYWdlLnNreWxpbmUubGluZWFnZXMuY29tYmkucGxvdCA8LSBnZ3Bsb3QoY29sbGVjdGVkLnNreWxpbmVzLmxpbmVhZ2VzLmluYy5mdWxsLCBhZXMoVGltZSxNZWRpYW4pKSArIAogIGdlb21fbGluZSgpICsgZ2VvbV9yaWJib24oYWVzKHltaW49TG93ZXIsIHltYXg9VXBwZXIpLCBhbHBoYT0wLjIsIGZpbGw9J2JsYWNrJykgKwogIHRoZW1lX2xpZ2h0KCkgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoc2VxKDE5ODAsMjAyMCwxMCkpLCBleHBhbmQ9YygwLjAxLDAuMDEpKSArIAogIHNjYWxlX3lfbG9nMTAoKSArIAogIGNvb3JkX2NhcnRlc2lhbih4PWMoMTk4MCwyMDIwKSkgKyAKICB0aGVtZS50ZXh0LnNpemUgKyBsYWJzKHk9IkluZmVycmVkIExpbmVhZ2VzIChwZXIgc3VibGluZWFnZSkiLCB4PSJZZWFyIikgKyAKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAyMDAwLCBjb2xvcj0nYmx1ZScsIGFscGhhPTAuNSkgKyAjYW5ub3RhdGUoInJlY3QiLHhtaW49MjAwMCx4bWF4PTIwMjAseW1pbj0wLHltYXg9MTAwMDAsYWxwaGE9MC4xLCBmaWxsPSdibHVlJykgKyAKICBmYWNldF9ncmlkKHN1YmxpbmVhZ2V+LikgKwogIHRoZW1lKHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3I9J3doaXRlJywgZmlsbD0nd2hpdGUnLGxpbmV0eXBlPSJzb2xpZCIpLCBzdHJpcC50ZXh0Lnk9ZWxlbWVudF90ZXh0KGNvbG9yID0gImdyZXkyNSIsYW5nbGU9MCwgc2l6ZT0xMCkpCgoKI0NhaXJvOjpDYWlybyhmaWxlPXBhc3RlMChGaWd1cmVfb3V0cHV0X2RpcmVjdG9yeSwgIlN1cHBsZW1lbnRhcnlfRmlndXJlOV9zdWJsaW5lYWdlc19za3lsaW5lc19fMDItMjAyMS5zdmciKSwgd2lkdGggPSAzMDAsIGhlaWdodCA9IDQwMCx0eXBlPSJzdmciLHVuaXRzID0gInB0IikKc3VibGluZWFnZS5za3lsaW5lLmNvbWJpLnBsb3QKI2Rldi5vZmYoKQpgYGAKCgoKCkxvb2sgYXQgQ2hyaXMgUnVpcydzIHRvb2wgZm9yIGV4dHJhY3RpbmcgdGhlIGRhdGUgZGlzdHJpYnV0aW5vIG9mIGEgcG9wdWxhdGlvbiBzaXplIGluY3JlYXNlXApSdW4gYXM6IFwKYHB5dGhvbjMgfi9zY3JpcHRzL3BvcHVsYXRpb25faW5jcmVhc2VfZGlzdHJpYnV0aW9uX0JFQVNULnB5IC1iMSAtdCBUUEEtdWJlci5yZW1hc2tlZC4yMDIwLTExLTEwLmdvb2Rjb3YyNS5ndWJiaW5zLldHUy5zdWJsaW5lYWdlLjEyLlN0cmljdC1Ta3lsaW5lX2NvbWJpbmVkLnRyZWVzIC1sIFRQQS11YmVyLnJlbWFza2VkLjIwMjAtMTEtMTAuZ29vZGNvdjI1Lmd1YmJpbnMuV0dTLnN1YmxpbmVhZ2UuMTIuU3RyaWN0LVNreWxpbmVfY29tYmluZWQubG9nIC1kIDIwMTkuNSAtbyBUUEEtdWJlci5yZW1hc2tlZC4yMDIwLTExLTEwLmdvb2Rjb3YyNS5ndWJiaW5zLldHUy5zdWJsaW5lYWdlLjEyLlN0cmljdC1Ta3lsaW5lX2NvbWJpbmVkLnBvcC1kaXN0cmlidXRpb25zLnR4dGAKXAoKQWxsIHBvcCBkaXN0cm9zCmBgYHtyfQojICJUUEEtdWJlcl9iZWFzdDJfc3RyaWN0LXNreWxpbmUtNTAwTV8xMHBvcF9jb21iaW5lZC5wb3AtZGlzdHJpYnV0aW9uc19wMTAwLnR4dCIKcG9wLmRpc3Ryby5zdWJzYW1wbGVkLmFsbC5maWxlIDwtIGJlYXN0Mi5mdWxsLnBvcGRpc3Ryby5wYXRoIAoKCiMgRG8gc2FtZSBmb3IgJ2xpbmVhZ2VzIHRocm91Z2ggdGltZScKY29sbGVjdGVkLnNreWxpbmUucG9wZGlzdHJvcyA8LSBOVUxMCmZvciAoc3VibGluZWFnZSBpbiBjKDEsMiw4KSkgewogIHNreWxpbmUucG9wZGlzdHJvIDwtIHJlYWQudGFibGUocGFzdGUwKHBvcC5kaXN0cm8ucGF0aCwiVFBBLXViZXIucmVtYXNrZWQuMjAyMC0xMS0xMC5nb29kY292MjUuZ3ViYmlucy5XR1Muc3VibGluZWFnZS5uZXcuIixzdWJsaW5lYWdlLCIubm9pbnYuU3RyaWN0LVNreWxpbmVfY29tYmluZWQucG9wLWV4cGFuc2lvbiIpLCBoZWFkZXI9VCwgc2VwPSJcdCIsIGNvbW1lbnQuY2hhcj0iIixzdHJpbmdzQXNGYWN0b3JzPUYpCiAgc2t5bGluZS5wb3BkaXN0cm8kc3VibGluZWFnZSA8LSBzdWJsaW5lYWdlIAogIGNvbGxlY3RlZC5za3lsaW5lLnBvcGRpc3Ryb3MgPC0gcmJpbmQoY29sbGVjdGVkLnNreWxpbmUucG9wZGlzdHJvcywgc2t5bGluZS5wb3BkaXN0cm8pCn0KIyBkbyAnQWxsJyBzZXBhcmF0ZWx5CnN1YmxpbmVhZ2UuYWxsLnNreWxpbmUucG9wLmRpc3RybyA8LSByZWFkLnRhYmxlKHBhc3RlMChwb3AuZGlzdHJvLnBhdGgscG9wLmRpc3Ryby5zdWJzYW1wbGVkLmFsbC5maWxlKSwgaGVhZGVyPVQsIHNlcD0iXHQiLCBjb21tZW50LmNoYXI9IiIsc3RyaW5nc0FzRmFjdG9ycz1GKQpzdWJsaW5lYWdlLmFsbC5za3lsaW5lLnBvcC5kaXN0cm8kc3VibGluZWFnZSA8LSAiQWxsIgpjb2xsZWN0ZWQuc2t5bGluZS5wb3BkaXN0cm9zIDwtIHJiaW5kKGNvbGxlY3RlZC5za3lsaW5lLnBvcGRpc3Ryb3Msc3VibGluZWFnZS5hbGwuc2t5bGluZS5wb3AuZGlzdHJvKQoKCmNvbGxlY3RlZC5za3lsaW5lLnBvcGRpc3Ryb3Mkc3VibGluZWFnZSA8LSBmYWN0b3IoY29sbGVjdGVkLnNreWxpbmUucG9wZGlzdHJvcyRzdWJsaW5lYWdlLCBsZXZlbHM9dW5pcXVlKGNvbGxlY3RlZC5za3lsaW5lLnBvcGRpc3Ryb3Mkc3VibGluZWFnZSkpCgp4LnRoZW1lLnN0cmlwLnBhcnRpYWwgPC0gdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueD0gZWxlbWVudF9ibGFuaygpKQoKCnBsb3QuY29sbGVjdGVkLnNreWxpbmUucG9wZGlzdHJvcy5zdGFydHMgPC0gZ2dwbG90KGNvbGxlY3RlZC5za3lsaW5lLnBvcGRpc3Ryb3NbY29sbGVjdGVkLnNreWxpbmUucG9wZGlzdHJvcyRJbmNyZWFzZV9kYXRlPjAsXSwgYWVzKHN1YmxpbmVhZ2UsSW5jcmVhc2VfZGF0ZSkpICsKICBnZW9tX3NpbmEoYWxwaGE9MC4yLGNvbG9yPSJncmV5ODAiLCBzaXplPTEpICsgCiAgZ2VvbV9ib3hwbG90KGFscGhhPTAuMCxvdXRsaWVyLnNoYXBlID0gTkEsIHdpZHRoPTAuMjUpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDE5MDAsMjAyMCkpICsgCiAgdGhlbWVfbGlnaHQoKSArIAogIHlsaW0oMTk0MCwyMDIwKSArCiAgZmFjZXRfZ3JpZChzdWJsaW5lYWdlfi4sIHNjYWxlcz0iZnJlZV95IikgKwogIGNvb3JkX2ZsaXAoKSArIHRoZW1lLnRleHQuc2l6ZSArCiAgdGhlbWUoc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvcj0nd2hpdGUnLCBmaWxsPSd3aGl0ZScsbGluZXR5cGU9InNvbGlkIiksIHN0cmlwLnRleHQueT1lbGVtZW50X3RleHQoY29sb3IgPSAiZ3JleTI1IixhbmdsZT0wLCBzaXplPTEwKSkgKwogICN5LnRoZW1lLnN0cmlwICsKICB0aGVtZShheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueT1lbGVtZW50X2JsYW5rKCkpICsKICBsYWJzKHk9IlllYXIiLCB4PSJEaXN0cmlidXRpb24gZGVuc2l0eSAoc3RhcnQgZGF0ZSBmb3IgNS1mb2xkIHBvcHVsYXRpb24gZXhwYW5zaW9uKSIpICsgCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMjAwMCwgY29sb3I9J2JsdWUnLCBhbHBoYT0wLjUpICsKICBOVUxMCiNwbG90LmNvbGxlY3RlZC5za3lsaW5lLnBvcGRpc3Ryb3Muc3RhcnRzCgoKcGxvdC5jb2xsZWN0ZWQuc2t5bGluZS5wb3BkaXN0cm9zLnN0YXJ0cy5kZW5zaXR5IDwtIGdncGxvdChjb2xsZWN0ZWQuc2t5bGluZS5wb3BkaXN0cm9zW2NvbGxlY3RlZC5za3lsaW5lLnBvcGRpc3Ryb3MkSW5jcmVhc2VfZGF0ZT4wLF0sIGFlcyhJbmNyZWFzZV9kYXRlKSkgKyAKICBnZW9tX2RlbnNpdHkoKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW09YygxOTAwLDIwMjApKSArCiAgI3NjYWxlX3hfY29udGludW91cyhicmVha3M9YyhzZXEoMTc0MCwyMDIwLDIwKSksIGV4cGFuZD1jKDAuMDEsMC4wMSksIGxpbWl0cz1jKDE3NDAsMjAyMCkpICsgCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKHNlcSgxNzQwLDIwMjAsMjApKSwgZXhwYW5kPWMoMC4wMSwwLjAxKSkgKyAKICBmYWNldF9ncmlkKHN1YmxpbmVhZ2V+Liwgc2NhbGVzPSJmcmVlX3kiKSArCiAgI2ZhY2V0X2dyaWQoc3VibGluZWFnZX4uKSArCiAgdGhlbWVfbGlnaHQoKSArIAogIHRoZW1lLnRleHQuc2l6ZSArIAogICN0aGVtZShheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueT1lbGVtZW50X2JsYW5rKCkpICsKICB0aGVtZShzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG9yPSd3aGl0ZScsIGZpbGw9J3doaXRlJyxsaW5ldHlwZT0ic29saWQiKSwgc3RyaXAudGV4dC55PWVsZW1lbnRfdGV4dChjb2xvciA9ICJncmV5MjUiLGFuZ2xlPTAsIHNpemU9MTApKSArCiAgbGFicyh4PSJZZWFyIiwgeT0iRGlzdHJpYnV0aW9uIGRlbnNpdHkgKHN0YXJ0IG9mIDItZm9sZCBwb3B1bGF0aW9uIGV4cGFuc2lvbikiKSArIAogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDIwMDAsIGNvbG9yPSdibHVlJywgYWxwaGE9MC41KSArCiAgTlVMTApwbG90LmNvbGxlY3RlZC5za3lsaW5lLnBvcGRpc3Ryb3Muc3RhcnRzLmRlbnNpdHkKCmBgYAoKCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9MTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpwbG90X2dyaWQoc3VibGluZWFnZS5za3lsaW5lLmNvbWJpLnBsb3QsICBzdWJsaW5lYWdlLnNreWxpbmUubGluZWFnZXMuY29tYmkucGxvdCwgcGxvdC5jb2xsZWN0ZWQuc2t5bGluZS5wb3BkaXN0cm9zLnN0YXJ0cy5kZW5zaXR5LG5jb2w9MywgYWxpZ249VCwgYXhpcz0ibHRiIixyZWxfd2lkdGhzPWMoNCwyLDMpLCBsYWJlbHM9YygnQSAtIEdlbmV0aWMgRGl2ZXJzaXR5JywnQiAtIExpbmVhZ2VzJywnQyAtIFBvcHVsYXRpb24gRXhwYW5zaW9uJyksIGxhYmVsX3NpemU9MTEsbGFiZWxfeT0xLCBsYWJlbF94PTAuMDEsIHNjYWxlPTAuOTUpIAoKYGBgCgpcCgoKI1dhbnQgdG8gbG9vayBhdCBkaXN0cmlidXRpb25zIHdpdGhpbiBzaW5nbGUgY291bnRyaWVzCgpFeHRyYWN0IFVLIGFuZCBDYW5hZGEgKGFsbCkgc3VidHJlZXMKYGBge3J9CgpzdWJ0cmVlLlVLLm1ldGEgPC0gVFBBLm1ldGExLjIucGluZWNvbmVbKFRQQS5tZXRhMS4yLnBpbmVjb25lJEdlb19Db3VudHJ5PT0iVUsiKSxjKCJDbGVhbmVkX2Zhc3RxX2lkIiwiU2FtcGxlX05hbWUiLCJTYW1wbGVfWWVhciIpXQpwLnN1YnRyZWUuVUsucjJ0IDwtIHBsb3Quc3VidHJlZS5SMlQoVFBBLk1MdHJlZSxzdWJ0cmVlLlVLLm1ldGEkU2FtcGxlX05hbWUsVFBBLm1ldGExLjIucGluZWNvbmUuaGF2ZWRhdGVzWyxjKCJTYW1wbGVfTmFtZSIsIlNhbXBsZV9ZZWFyIildKQoKc3VidHJlZS5CQy5tZXRhIDwtIFRQQS5tZXRhMS4yLnBpbmVjb25lWyhUUEEubWV0YTEuMi5waW5lY29uZSRHZW9fUmVnaW9uPT0iQnJpdGlzaF9Db2x1bWJpYSIpLGMoIkNsZWFuZWRfZmFzdHFfaWQiLCJTYW1wbGVfTmFtZSIsIlNhbXBsZV9ZZWFyIildCnAuc3VidHJlZS5CQy5yMnQgPC0gcGxvdC5zdWJ0cmVlLlIyVChUUEEuTUx0cmVlLHN1YnRyZWUuQkMubWV0YSRTYW1wbGVfTmFtZSxUUEEubWV0YTEuMi5waW5lY29uZS5oYXZlZGF0ZXNbLGMoIlNhbXBsZV9OYW1lIiwiU2FtcGxlX1llYXIiKV0pCgpwbG90X2dyaWQocC5zdWJ0cmVlLlVLLnIydCwgcC5zdWJ0cmVlLkJDLnIydCwgbnJvdz0yKQpgYGAKCkV4dHJhY3QgVUsgYW5kIENhbmFkYSBzdWJ0cmVlcyBmb3IgU3VibGluZWFnZSAyIG9ubHkKYGBge3J9CgpzdWJsaW5lYWdlLjIuVUsubWV0YSA8LSBUUEEubWV0YTEuMi5waW5lY29uZVsoVFBBLm1ldGExLjIucGluZWNvbmUkVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2U9PTIgJiBUUEEubWV0YTEuMi5waW5lY29uZSRHZW9fQ291bnRyeT09IlVLIiksYygiQ2xlYW5lZF9mYXN0cV9pZCIsIlNhbXBsZV9OYW1lIiwiU2FtcGxlX1llYXIiKV0KcC5zdWJsaW4uMi5VSy5yMnQgPC0gcGxvdC5zdWJ0cmVlLlIyVChUUEEuTUx0cmVlLHN1YmxpbmVhZ2UuMi5VSy5tZXRhJFNhbXBsZV9OYW1lLFRQQS5tZXRhMS4yLnBpbmVjb25lLmhhdmVkYXRlc1ssYygiU2FtcGxlX05hbWUiLCJTYW1wbGVfWWVhciIpXSkKCnN1YmxpbmVhZ2UuMi5CQy5tZXRhIDwtIFRQQS5tZXRhMS4yLnBpbmVjb25lWyhUUEEubWV0YTEuMi5waW5lY29uZSRUUEEucGluZWNvbmUuc3VibGluZWFnZT09MiAmIFRQQS5tZXRhMS4yLnBpbmVjb25lJEdlb19SZWdpb249PSJCcml0aXNoX0NvbHVtYmlhIiksYygiQ2xlYW5lZF9mYXN0cV9pZCIsIlNhbXBsZV9OYW1lIiwiU2FtcGxlX1llYXIiKV0KcC5zdWJsaW4uMi5CQy5yMnQgPC0gcGxvdC5zdWJ0cmVlLlIyVChUUEEuTUx0cmVlLHN1YmxpbmVhZ2UuMi5CQy5tZXRhJFNhbXBsZV9OYW1lLFRQQS5tZXRhMS4yLnBpbmVjb25lLmhhdmVkYXRlc1ssYygiU2FtcGxlX05hbWUiLCJTYW1wbGVfWWVhciIpXSkKCnBsb3RfZ3JpZChwLnN1Ymxpbi4yLlVLLnIydCwgcC5zdWJsaW4uMi5CQy5yMnQsIG5yb3c9MikKCmBgYAoKU28gdmVyeSBsaXR0bGUgdGVtcG9yYWwgc2lnbmFsIGhlcmUsIHBhcnRpY3VsYXJseSBmb3IgdGhlIFVLIGRhdGEgKG9ubHkgNyB5ZWFycykuIE5vdCByZWFsaXN0aWMgdG8gYW5hbHlzZSB0aGlzIHdheS4KCgoKCkxvb2sgYXQgY292ZXJhZ2Ugc3RhdGlzdGljcyAKYGBge3J9CiMgRm9yIHRoZSBsYXJnZSBsb3cgY292IGRhdGFzZXQKbnJvdyhUUEEubWV0YTEuMikKbWVhbihhcy5udW1lcmljKFRQQS5tZXRhMS4yJE1lYW5fbWFwcGluZ19jb3ZlcmFnZSksIG5hLnJtPVQpCm1heChhcy5udW1lcmljKFRQQS5tZXRhMS4yJE1lYW5fbWFwcGluZ19jb3ZlcmFnZSkpCm1pbihhcy5udW1lcmljKFRQQS5tZXRhMS4yJE1lYW5fbWFwcGluZ19jb3ZlcmFnZSkpCgooMS1tZWFuKGFzLm51bWVyaWMoVFBBLm1ldGExLjIkYFByb3BvcnRpb24tTl8+NV9tYXBwaW5nK21hc2tpbmdfTmljaG9sc2ApLCBuYS5ybT1UKSkqMTAwCigxLW1heChhcy5udW1lcmljKFRQQS5tZXRhMS4yJGBQcm9wb3J0aW9uLU5fPjVfbWFwcGluZyttYXNraW5nX05pY2hvbHNgKSwgbmEucm09VCkpKjEwMAooMS1taW4oYXMubnVtZXJpYyhUUEEubWV0YTEuMiRgUHJvcG9ydGlvbi1OXz41X21hcHBpbmcrbWFza2luZ19OaWNob2xzYCksIG5hLnJtPVQpKSoxMDAKCgojIEZvciB0aGUgY3VyYXRlZCBkYXRhc2V0Cm5yb3coVFBBLm1ldGExLjIucGluZWNvbmUpCm1lYW4oYXMubnVtZXJpYyhUUEEubWV0YTEuMi5waW5lY29uZSRNZWFuX21hcHBpbmdfY292ZXJhZ2UpLCBuYS5ybT1UKQptYXgoYXMubnVtZXJpYyhUUEEubWV0YTEuMi5waW5lY29uZSRNZWFuX21hcHBpbmdfY292ZXJhZ2UpKQptaW4oYXMubnVtZXJpYyhUUEEubWV0YTEuMi5waW5lY29uZSRNZWFuX21hcHBpbmdfY292ZXJhZ2UpKQoKKDEtbWVhbihhcy5udW1lcmljKFRQQS5tZXRhMS4yLnBpbmVjb25lJGBQcm9wb3J0aW9uLU5fPjVfbWFwcGluZyttYXNraW5nX05pY2hvbHNgKSwgbmEucm09VCkpKjEwMAooMS1tYXgoYXMubnVtZXJpYyhUUEEubWV0YTEuMi5waW5lY29uZSRgUHJvcG9ydGlvbi1OXz41X21hcHBpbmcrbWFza2luZ19OaWNob2xzYCksIG5hLnJtPVQpKSoxMDAKYGBgCgoKYGBge3J9CigxLW1pbihhcy5udW1lcmljKFRQQS5tZXRhMS4yLnBpbmVjb25lJGBQcm9wb3J0aW9uLU5fPjVfbWFwcGluZyttYXNraW5nX05pY2hvbHNgKSwgbmEucm09VCkpKjEwMApgYGAKCgoKUXVpY2tseSBsb29rIGF0IGxpbmVhZ2UgYXNzb2NpYXRpb24gb2YgcmVjb21iaW5hdGlvbiBibG9ja3MKYGBge3J9CiMgRGVmaW5lIGFuZCByZWFkIGluIHJlY29tYmluYXRpb24gaW5mbwpyZWNvbWJpbmF0aW9uX2V2ZW50LmRhdGEgPC0gcmVhZHhsOjpyZWFkX2V4Y2VsKHJlY29tYmluYXRpb25fZXZlbnQuZmlsZSxzaGVldD0iUmVjb21iaW5hdGlvbl9EYXRhIikKCiMgU3Vic2V0IHRvIGd1YmJpbnMgZmlsdGVyZWQgcmVnaW9ucyBhbmQgb3JkZXIgYnkgZXZlbnQKcmVjb21iaW5hdGlvbl9ldmVudC5kYXRhLmd1YmJpbnMgPC0gcmVjb21iaW5hdGlvbl9ldmVudC5kYXRhW3JlY29tYmluYXRpb25fZXZlbnQuZGF0YSRHdWJiaW5zX0V2ZW50X0lEIT0iLSIsXQpyZWNvbWJpbmF0aW9uX2V2ZW50LmRhdGEuZ3ViYmlucyA8LSByZWNvbWJpbmF0aW9uX2V2ZW50LmRhdGEuZ3ViYmluc1shaXMubmEocmVjb21iaW5hdGlvbl9ldmVudC5kYXRhLmd1YmJpbnMkbGluZV9vcmRlciksXQpyZWNvbWJpbmF0aW9uX2V2ZW50LmRhdGEuZ3ViYmlucyA8LSByZWNvbWJpbmF0aW9uX2V2ZW50LmRhdGEuZ3ViYmluc1tvcmRlcihhcy5udW1lcmljKHJlY29tYmluYXRpb25fZXZlbnQuZGF0YS5ndWJiaW5zJEd1YmJpbnNfRXZlbnRfSUQpKSxdCgojIGNvbnZlcnQgcGVyLWV2ZW50IGxpc3QgaW50byBhIG1hdHJpeApyZWNvbWJpbmF0aW9uX2V2ZW50LmRhdGEuZ3ViYmlucy5tYXRyaXggPC0gcmVzaGFwZTI6OmRjYXN0KHJlc2hhcGUyOjptZWx0KHN0cnNwbGl0KHJlY29tYmluYXRpb25fZXZlbnQuZGF0YS5ndWJiaW5zJFNhbXBsZUlEcywiLCIpKSxMMX52YWx1ZSkKY29sbmFtZXMocmVjb21iaW5hdGlvbl9ldmVudC5kYXRhLmd1YmJpbnMubWF0cml4KVsxXSA8LSAiR3ViYmluc19FdmVudF9JRCIKCiMgbWVsdCBtYXRyaXggaW50byBsb25nZm9ybQpyZWNvbWJpbmF0aW9uX2V2ZW50LmRhdGEuZ3ViYmlucy5tYXRyaXgubWVsdCA8LSByZXNoYXBlMjo6bWVsdChyZWNvbWJpbmF0aW9uX2V2ZW50LmRhdGEuZ3ViYmlucy5tYXRyaXgsaWQudmFycz0iR3ViYmluc19FdmVudF9JRCIpCiMgaW5mZXIgcHJlc2VuY2UvYWJzZW5jZQpyZWNvbWJpbmF0aW9uX2V2ZW50LmRhdGEuZ3ViYmlucy5tYXRyaXgubWVsdCRiaW5hcnkgPC0gaWZlbHNlKGlzLm5hKHJlY29tYmluYXRpb25fZXZlbnQuZGF0YS5ndWJiaW5zLm1hdHJpeC5tZWx0JHZhbHVlKSwwLDEpCmNvbG5hbWVzKHJlY29tYmluYXRpb25fZXZlbnQuZGF0YS5ndWJiaW5zLm1hdHJpeC5tZWx0KSA8LSBjKCJHdWJiaW5zX0V2ZW50X0lEIiwiU2FtcGxlX05hbWUiLCJ2YWx1ZSIsInJlY29tYi5wcmVzZW50IikKCiMgTWFrZSBhIGJpbmFyeSBwcmVzZW5jZS9hYnNlbmNlIG1hdHJpeCBvcmdhbmlzZWQgYnkgc2FtcGxlIChmb3IgcG9zc2libGUgcGxvdHRpbmcgd2l0aCBnZ3RyZWUpCnJlY29tYmluYXRpb25fZXZlbnQuZGF0YS5ndWJiaW5zLm1hdHJpeC5iaW5hcnkgPC0gcmVzaGFwZTI6OmRjYXN0KHJlY29tYmluYXRpb25fZXZlbnQuZGF0YS5ndWJiaW5zLm1hdHJpeC5tZWx0WyxjKCJHdWJiaW5zX0V2ZW50X0lEIiwiU2FtcGxlX05hbWUiLCJyZWNvbWIucHJlc2VudCIpXSwgU2FtcGxlX05hbWV+R3ViYmluc19FdmVudF9JRCkKCgojIE1lcmdlIGluIExpbmVhZ2UgYW5kIFBpbmVjb25lIGluZm9ybWF0aW9uCnJlY29tYmluYXRpb25fZXZlbnQuZGF0YS5ndWJiaW5zLm1hdHJpeC5tZWx0IDwtIHBseXI6OmpvaW4ocmVjb21iaW5hdGlvbl9ldmVudC5kYXRhLmd1YmJpbnMubWF0cml4Lm1lbHRbYygiR3ViYmluc19FdmVudF9JRCIsIlNhbXBsZV9OYW1lIiwicmVjb21iLnByZXNlbnQiKV0sVFBBLm1ldGExLjIucGluZWNvbmVbLGMoIlNhbXBsZV9OYW1lIiwiVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UiLCJUUEFfTGluZWFnZSIpXSwgYnk9IlNhbXBsZV9OYW1lIikKCgpyZWNvbWJpbmF0aW9uX2V2ZW50LmJ5LkxpbmVhZ2UgPC0gcmVjb21iaW5hdGlvbl9ldmVudC5kYXRhLmd1YmJpbnMubWF0cml4Lm1lbHQgJT4lIGRwbHlyOjpncm91cF9ieShHdWJiaW5zX0V2ZW50X0lELCBUUEFfTGluZWFnZSkgJT4lIAogIGRwbHlyOjpzdW1tYXJpc2UoU3VtPXN1bShyZWNvbWIucHJlc2VudCkpCiNyZWNvbWJpbmF0aW9uX2V2ZW50LmJ5LkxpbmVhZ2VbcmVjb21iaW5hdGlvbl9ldmVudC5ieS5MaW5lYWdlJFN1bSE9MCxdCgpyZWNvbWJpbmF0aW9uX2V2ZW50LmJ5LnN1YmxpbmVhZ2UgPC0gcmVjb21iaW5hdGlvbl9ldmVudC5kYXRhLmd1YmJpbnMubWF0cml4Lm1lbHQgJT4lIGRwbHlyOjpncm91cF9ieShHdWJiaW5zX0V2ZW50X0lELCBUUEEucGluZWNvbmUuc3VibGluZWFnZSkgJT4lIAogIGRwbHlyOjpzdW1tYXJpc2UoU3VtPXN1bShyZWNvbWIucHJlc2VudCkpCnJlY29tYmluYXRpb25fZXZlbnQuYnkuc3VibGluZWFnZVtyZWNvbWJpbmF0aW9uX2V2ZW50LmJ5LnN1YmxpbmVhZ2UkU3VtIT0wLF0KCgpgYGAKCmBgYHtyfQpyZWNvbWJpbmF0aW9uX2V2ZW50LmRhdGEuZ3ViYmlucy5tYXRyaXgubWVsdCA8LSBwbHlyOjpqb2luKHJlY29tYmluYXRpb25fZXZlbnQuZGF0YS5ndWJiaW5zLm1hdHJpeC5tZWx0LCByZWNvbWJpbmF0aW9uX2V2ZW50LmRhdGEuZ3ViYmluc1ssYygiR3ViYmluc19FdmVudF9JRCIsIkJsb2NrX1N0YXJ0IiwiQmxvY2tfRW5kIildLCBieT0iR3ViYmluc19FdmVudF9JRCIpCgpyZWNvbWJpcGxvdC50aXAub3JkZXIgPC0gZGF0YS5mcmFtZShTYW1wbGVfTmFtZT1nZXRfdGF4YV9uYW1lKGdndHJlZShUUEEuTUx0cmVlKSksc3RyaW5nc0FzRmFjdG9ycyA9IEYpIApyZWNvbWJpcGxvdC50aXAub3JkZXIkb3JkZXIgPC0gYygxOm5yb3cocmVjb21iaXBsb3QudGlwLm9yZGVyKSkKcmVjb21iaXBsb3QudGlwLm9yZGVyJG9yZGVyMiA8LSByZXYoYygxOm5yb3cocmVjb21iaXBsb3QudGlwLm9yZGVyKSkpCnJlY29tYmlwbG90LnRpcC5vcmRlciA8LSBwbHlyOjpqb2luKHJlY29tYmlwbG90LnRpcC5vcmRlcixyZWNvbWJpbmF0aW9uX2V2ZW50LmRhdGEuZ3ViYmlucy5tYXRyaXgubWVsdCwgYnk9IlNhbXBsZV9OYW1lIiwgdHlwZT0iZnVsbCIpCgoKcC5yZWNvbWJpLnBsb3QgPC0gZ2dwbG90KHJlY29tYmlwbG90LnRpcC5vcmRlcikgKwogIGdlb21fcmVjdChhZXMoeW1pbj1vcmRlcjItMC41LHltYXg9b3JkZXIyKzAuNSwgeG1pbj1hcy5udW1lcmljKEJsb2NrX1N0YXJ0KSwgeG1heD1hcy5udW1lcmljKEJsb2NrX0VuZCkpLCBhbHBoYT0wLjUpICsKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbT1jKDEsMTEzOTU2OSkpICsKICB0aGVtZV9taW5pbWFsKCkKCiNUUEEuTUx0cmVlLmdndHJlZS50aXBwb2ludAoKCiNnZ3RyZWUoVFBBLk1MdHJlZSkgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKQpwbG90X2dyaWQoZ2d0cmVlKFRQQS5NTHRyZWUpLCBwLnJlY29tYmkucGxvdCwgYWxpZ249VCwgYXhpcz0idGIiLCByZWxfd2lkdGhzID0gYygxLDIpKQpgYGAKCmBgYHtyfQoKVFBBLk1MdHJlZS50ZXN0cGxvdCA8LSBnZ3RyZWUoVFBBLk1MdHJlZSkKI2ZhY2V0X3Bsb3QoVFBBLk1MdHJlZS50ZXN0cGxvdCwgcGFuZWw9Ikdlbm9tZV9CbG9ja3MiLCBkYXRhPXJlY29tYmlwbG90LnRpcC5vcmRlciwgZ2VvbV9yZWN0LCBtYXBwaW5nPWFlcyh4bWluPUJsb2NrX1N0YXJ0LCB4bWF4PUJsb2NrX0VuZCwgZmlsbD1UUEFfTGluZWFnZSkpCgpgYGAKCmBgYHtyfQpyZWNvbWJpbmluZy5nZW5lcyA8LSBjKCJUUEFTU19SUzAwMDQwIiwgIlRQQVNTX1JTMDAwNDUiLCAiVFBBU1NfUlMwMDU5MCIsICJUUEFTU19SUzAwNjc1IiwgIlRQQVNTX1JTMDE1NTUiLCAiVFBBU1NfUlMwMTU2NSIsICJUUEFTU19SUzAxNTcwIiwgIlRQQVNTX1JTMDIxMjUiLCAiVFBBU1NfUlMwMjI5MCIsICJUUEFTU19SUzAyNzAwIiwgIlRQQVNTX1JTMDMwMjAiLCAiVFBBU1NfUlMwMzA3MCIsICJUUEFTU19SUzAzMDc1IiwgIlRQQVNTX1JTMDQyNDAiLCAiVFBBU1NfUlMwNDI0NSIsICJUUEFTU19SUzA0MjUwIiwgIlRQQVNTX1JTMDQyNzUiLCAiVFBBU1NfUlMwNTM4NSIsICJUUEFTU19SUzA1MTEwIiwgIlRQQVNTX1JTMDUyMTAsVFBBU1NfUlMwMDY4NSxUUEFTU19SUzAwNzA1LFRQQVNTX1JTMDA2OTAsVFBBU1NfUlMwMDY4MCxUUEFTU19SUzAwNzAwLFRQQVNTX1JTMDA2NzUsVFBBU1NfUlMwMDY2NSxUUEFTU19SUzAwNjcwIiwgIlRQQVNTX1JTMDA3MDUsVFBBU1NfUlMwMDY4NSxUUEFTU19SUzAwNjkwLFRQQVNTX1JTMDA3MDAiLCAiVFBBU1NfUlMwMDcwNSIsICJUUEFTU19SUzAwNzA1IiwgIlRQQVNTX1JTMDA3MDUiLCAiVFBBU1NfUlMwMDkwNSIsICJUUEFTU19SUzAxNjAwIiwgIlRQQVNTX1JTMDE2MDAiLCAiVFBBU1NfUlMwMjI2NSIsICJUUEFTU19SUzAyMjY1IiwgIlRQQVNTX1JTMDIyNjUiLCAiVFBBU1NfUlMwMjM1MCxUUEFTU19SUzAyMzU1IiwgIlRQQVNTX1JTMDIzNzUiLCAiVFBBU1NfUlMwMjUyNSIsICJUUEFTU19SUzAyNzYwLFRQQVNTX1JTMDI3NTUiLCAiVFBBU1NfUlMwMzA1NSxUUEFTU19SUzAzMDY1LFRQQVNTX1JTMDMwNjAiLCAiVFBBU1NfUlMwMzA2NSIsICJUUEFTU19SUzA0NzgwLFRQQVNTX1JTMDQ3OTAsVFBBU1NfUlMwNDc4NSxUUEFTU19SUzA0Nzc1IiwgIlRQQVNTX1JTMDUxMDAsVFBBU1NfUlMwNTEwNSIpCgoKcmVjb21iaW5pbmcuZ2VuZXMgPC0gYygiVFBBU1NfUlMwNTIxMCxUUEFTU19SUzAwNjg1LFRQQVNTX1JTMDA3MDUsVFBBU1NfUlMwMDY5MCxUUEFTU19SUzAwNjgwLFRQQVNTX1JTMDA3MDAsVFBBU1NfUlMwMDY3NSxUUEFTU19SUzAwNjY1LFRQQVNTX1JTMDA2NzAiLCAiVFBBU1NfUlMwMDcwNSxUUEFTU19SUzAwNjg1LFRQQVNTX1JTMDA2OTAsVFBBU1NfUlMwMDcwMCIsICJUUEFTU19SUzAwNzA1IiwgIlRQQVNTX1JTMDA3MDUiLCAiVFBBU1NfUlMwMDcwNSIsICJUUEFTU19SUzAwOTA1IiwgIlRQQVNTX1JTMDE2MDAiLCAiVFBBU1NfUlMwMTYwMCIsICJUUEFTU19SUzAyMjY1IiwgIlRQQVNTX1JTMDIyNjUiLCAiVFBBU1NfUlMwMjI2NSIsICJUUEFTU19SUzAyMzUwLFRQQVNTX1JTMDIzNTUiLCAiVFBBU1NfUlMwMjM3NSIsICJUUEFTU19SUzAyNTI1IiwgIlRQQVNTX1JTMDI3NjAsVFBBU1NfUlMwMjc1NSIsICJUUEFTU19SUzAzMDU1LFRQQVNTX1JTMDMwNjUsVFBBU1NfUlMwMzA2MCIsICJUUEFTU19SUzAzMDY1IiwgIlRQQVNTX1JTMDQ3ODAsVFBBU1NfUlMwNDc5MCxUUEFTU19SUzA0Nzg1LFRQQVNTX1JTMDQ3NzUiLCAiVFBBU1NfUlMwNTEwMCxUUEFTU19SUzA1MTA1IikKCnVuaXF1ZSh1bmxpc3Qoc3Ryc3BsaXQocmVjb21iaW5pbmcuZ2VuZXMsIiwiKSkpCgoKYGBgCgoKVGlwIGRhdGUgcmFuZG9taXNhdGlvbiB1c2luZyBUaXBEYXRpbmdCRUFTVCBwYWNrYWdlCmBgYHtyfQpsaWJyYXJ5KFRpcERhdGluZ0JlYXN0KQoKIyBzZXR3ZCgiL1VzZXJzL21iMjkvVHJlcG9uZW1hL0V4cGFuZGVkX0dsb2JhbF9TZXF1ZW5jaW5nL0FuYWx5c2lzL0dsb2JhbF9UUEFfdWJlci1hbmFseXNpc18yMDIwX3YyL3BoeWxvL2dvb2RfY292X2RhdGFzZXQvZ3ViYmluc18yLjQuMV9fMjAtMTEtMTAvYmVhc3QvYmVhc3QyX2Z1bGwtdHJlZV8yMDIwLTExLTI1L2JlYXV0aS90aXBfcmFuZG9taXNhdGlvbi8iKQoKI3NldHdkKCIvVXNlcnMvbWIyOS9UcmVwb25lbWEvRXhwYW5kZWRfR2xvYmFsX1NlcXVlbmNpbmcvQW5hbHlzaXMvR2xvYmFsX1RQQV91YmVyLWFuYWx5c2lzXzIwMjBfdjIvcGh5bG8vZ29vZF9jb3ZfZGF0YXNldC9ndWJiaW5zXzIuNC4xX18yMC0xMS0xMC9iZWFzdC9iZWFzdDJfZnVsbC10cmVlXzIwMjAtMTEtMjUvYmVhdXRpL3RpcF9yYW5kb21pc2F0aW9uL3JlcnVuX01FTC0xXzAxLTAzLTIwMjEvIikKCm9yaWdpbmFsLnhtbC5maWxlIDwtICJiZWFzdDJfU3RyaWN0LVNreWxpbmVfRnVsbDUwME1fK3NpdGVzXzEiCgojIEdlbmVyYXRlIHRpcGRhdGUtcmFuZG9taXNlZCB4bWwgZmlsZXMgZnJvbSBvcmlnaW5hbCBCRUFTVDIgeG1sCiNUaXBEYXRpbmdCZWFzdDo6UmFuZG9tRGF0ZXMobmFtZT0iYmVhc3QyX1N0cmljdC1Ta3lsaW5lX0Z1bGw1MDBNXytzaXRlc18xIixyZXBzPTIwKQoKIyBBbGwgZGF0YXNldHMgcnVuIGluIEJFQVNUMi4gCgojIEFmdGVyIDIwIHJ1bnMgKHRvb2sgfjIgd2Vla3MpIGVuc3VyZSBhbGwgZmlsZXMgYXJlIGNvcnJlY3RseSBsYWJlbGxlZCBhbmQgcHVsbCBpbiBkYXRhCiNUaXBEYXRpbmdCZWFzdDo6UGxvdERSVChuYW1lPSJiZWFzdDJfU3RyaWN0LVNreWxpbmVfRnVsbDUwME1fK3NpdGVzXzEiLHJlcHM9MjAsYnVybmluPTAuMSkKCiMgVGhhdCBwbG90IGlzbid0IHZlcnkgbmljZSwgYnV0IHRoZSBwYWNrYWdlIGFsc28gZ2VuZXJhdGVzIGEgY3N2IGZpbGUgY29udGFpbmluZyB0aGUgdmFsdWVzIG9mIGludGVyZXN0IHRoYXQgd2UgY2FuIHBsb3QKCnJhbmRvbXRpcC5zdW1tYXJ5IDwtIHJlYWQuY3N2KHJhbmRvbS50aXAuc3VtbWFyeS5maWxlLGhlYWRlcj1UKQoKcmFuZG9tdGlwLnN1bW1hcnkkRGF0YSA8LSBpZmVsc2UocmFuZG9tdGlwLnN1bW1hcnkkY2FsaWJyPT0wLCJSZWFsIiwiUmFuZG9taXNlZCIpCgpwLnRpcGRhdGVyYW5kb21pc2F0aW9uLm5vcm1hbCA8LSBnZ3Bsb3QocmFuZG9tdGlwLnN1bW1hcnkpICsKICBnZW9tX3BvaW50cmFuZ2UoYWVzKHg9Y2FsaWJyLCB5PW1lZGlhbix5bWluID0gbG93ZXJIUEQsIHltYXggPSBIaWdoZXJIUEQsY29sb3I9RGF0YSkpICsKICB0aGVtZV9saWdodCgpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKSArCiAgbGFicyh4PSJSZXBsaWNhdGUiLCB5PSJDbG9jayBSYXRlIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdD1yYW5kb210aXAuc3VtbWFyeSRsb3dlckhQRFsxXSxhbHBoYT0wLjUpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9cmFuZG9tdGlwLnN1bW1hcnkkSGlnaGVySFBEWzFdLGFscGhhPTAuNSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdD1yYW5kb210aXAuc3VtbWFyeSRIaWdoZXJIUERbMThdLGFscGhhPTAuNSkgKwogIE5VTEwKI3AudGlwZGF0ZXJhbmRvbWlzYXRpb24ubm9ybWFsCgpwLnRpcGRhdGVyYW5kb21pc2F0aW9uLmxvZzEwIDwtIGdncGxvdChyYW5kb210aXAuc3VtbWFyeSkgKwogIGdlb21fcG9pbnRyYW5nZShhZXMoeD1jYWxpYnIsIHk9bWVkaWFuLHltaW4gPSBsb3dlckhQRCwgeW1heCA9IEhpZ2hlckhQRCxjb2xvcj1EYXRhKSkgKwogIHRoZW1lX2xpZ2h0KCkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb249InRvcCIpICsKICAjc2NhbGVfeV9sb2cxMCgpICsKICBzY2FsZV95X2xvZzEwKGJyZWFrcyA9IHRyYW5zX2JyZWFrcygibG9nMTAiLCBmdW5jdGlvbih4KSAxMF54KSwKICAgICAgICAgICAgICBsYWJlbHMgPSB0cmFuc19mb3JtYXQoImxvZzEwIiwgbWF0aF9mb3JtYXQoMTBeLngpKSkgKwogIGxhYnMoeD0iUmVwbGljYXRlIiwgeT0iQ2xvY2sgUmF0ZSIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9cmFuZG9tdGlwLnN1bW1hcnkkbG93ZXJIUERbMV0sYWxwaGE9MC41KSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PXJhbmRvbXRpcC5zdW1tYXJ5JEhpZ2hlckhQRFsxXSxhbHBoYT0wLjUpICsKICBOVUxMCgojQ2Fpcm86OkNhaXJvKGZpbGU9cGFzdGUwKEZpZ3VyZV9vdXRwdXRfZGlyZWN0b3J5LCAiU3VwcGxlbWVudGFyeV9GaWd1cmUxOV90aXBkYXRlLXJhbmRvbWlzYXRpb24uc3ZnIiksIHdpZHRoID0gNTUwLCBoZWlnaHQgPSAzMDAsdHlwZT0ic3ZnIix1bml0cyA9ICJwdCIpCnAudGlwZGF0ZXJhbmRvbWlzYXRpb24ubG9nMTAKI2Rldi5vZmYoKQoKcmFuZG9tdGlwLnN1bW1hcnlbcmFuZG9tdGlwLnN1bW1hcnkkY2FsaWJyPT0wLCJtZWRpYW4iXQptYXgocmFuZG9tdGlwLnN1bW1hcnlbcmFuZG9tdGlwLnN1bW1hcnkkY2FsaWJyIT0wLCJtZWRpYW4iXSkKYGBgCgoKRGlzdHJpYnV0aW9uIG9mIFJhYmJpdCBwYXNzYWdlZCBzdHJhaW5zCmBgYHtyfQoKc3VibGluZWFnZS5wYXNzYWdlZC5zYW1wbGVzIDwtIGRhdGEuZnJhbWUoVFBBLm1ldGExLjIucGluZWNvbmUgJT4lIGRwbHlyOjpncm91cF9ieShUUEEucGluZWNvbmUuc3VibGluZWFnZSxEaXJlY3RfZnJvbV9jbGluKSAlPiUKICBkcGx5cjo6c3VtbWFyaXNlKGNvdW50PW4oKSksc3RyaW5nc0FzRmFjdG9ycyA9IEYpCgpzdWJsaW5lYWdlLnBhc3NhZ2VkLnNhbXBsZXMkVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UgPC0gZmFjdG9yKHN1YmxpbmVhZ2UucGFzc2FnZWQuc2FtcGxlcyRUUEEucGluZWNvbmUuc3VibGluZWFnZSwgbGV2ZWxzPXJldihzdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZSkpCgpwLnN1YmxpbmVhZ2UucmFiYml0LnBhc3NhZ2UgPC0gZ2dwbG90KHN1YmxpbmVhZ2UucGFzc2FnZWQuc2FtcGxlcywgYWVzKGNvdW50LCBUUEEucGluZWNvbmUuc3VibGluZWFnZSwgZmlsbD1EaXJlY3RfZnJvbV9jbGluKSkgKwogIGdlb21fYmFyaChzdGF0PSJpZGVudGl0eSIscG9zaXRpb249ImZpbGwiLCB3aWR0aD0wLjc1KSArCiAgdGhlbWVfbGlnaHQoKSArCiAgdGhlbWUudGV4dC5zaXplICsgdGhlbWUobGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjY1LCJsaW5lIiksbGVnZW5kLnBvc2l0aW9uPSdib3R0b20nKSArCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZT0iRGlyZWN0IGZyb20gQ2xpbmljYWwgc2FtcGxlXG4obm8gcmFiYml0IHBhc3NhZ2UpIix2YWx1ZXM9YygiZ3JleTgwIiwiZ3JleTEwIikpICsKICBsYWJzKHk9IlN1YmxpbmVhZ2UiLCB4PSJQcm9wb3J0aW9uIHBhc3NhZ2VkIikKCiNwLnN1YmxpbmVhZ2UucmFiYml0LnBhc3NhZ2UKCgojZGF0YS5mcmFtZShyb3cubmFtZXM9VFBBLm1ldGExLjIucGluZWNvbmUkU2FtcGxlX05hbWUsIERpcmVjdF9TZXF1ZW5jZWQ9VFBBLm1ldGExLjIucGluZWNvbmUkRGlyZWN0X2Zyb21fY2xpbiwgc3RyaW5nc0FzRmFjdG9ycz1GKQoKcC5NTHRyZWUucmFiYml0LnBhc3NhZ2UuZGlzdHJvcyA8LSBnaGVhdG1hcChUUEEuTUx0cmVlLmdndHJlZS50aXBwb2ludCArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpLAogICAgICAgICAgICAgICBkYXRhLmZyYW1lKHJvdy5uYW1lcz1UUEEubWV0YTEuMi5waW5lY29uZSRTYW1wbGVfTmFtZSwgYERpcmVjdCBmcm9tIGNsaW5pY2FsYD1UUEEubWV0YTEuMi5waW5lY29uZSREaXJlY3RfZnJvbV9jbGluLCBzdHJpbmdzQXNGYWN0b3JzPUYpLCBjb2xvcj0nZ3JleTcwJyx3aWR0aD0wLjA3NSxvZmZzZXQ9MC4wMDAwMDcyNSwgY29sbmFtZXNfYW5nbGU9LTQ1LGNvbG5hbWVzX29mZnNldF95PTAsIGhqdXN0PTAsZm9udC5zaXplPTIpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZT0iRGlyZWN0IGZyb20gY2xpbmljYWwgc2FtcGxlIix2YWx1ZXM9YygiZ3JleTgwIiwiZ3JleTEwIikpICsKICB0aGVtZS50ZXh0LnNpemUgKyB0aGVtZShsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNjUsImxpbmUiKSxsZWdlbmQucG9zaXRpb249J3JpZ2h0JykKCnAuc3VibGluZWFnZS5yYWJiaXQucGFzc2FnZS50b3Byb3cgPC0gcGxvdF9ncmlkKCcnLHAuc3VibGluZWFnZS5yYWJiaXQucGFzc2FnZSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0nbm9uZScpLCcnLG5jb2w9MSxyZWxfaGVpZ2h0cz1jKDEsMywxKSkKCnAucmFiYml0LnBhc3NhZ2UuZGlzdHJvcy5jb21iaW5hdGlvbiA8LSBwbG90X2dyaWQocC5NTHRyZWUucmFiYml0LnBhc3NhZ2UuZGlzdHJvcywgcC5zdWJsaW5lYWdlLnJhYmJpdC5wYXNzYWdlLnRvcHJvdywgcmVsX3dpZHRocyA9IGMoMywxKSwgbGFiZWxzPWMoJ0EnLCdCJyksIGxhYmVsX3NpemU9MTEpCgoKI0NhaXJvOjpDYWlybyhmaWxlPXBhc3RlMChGaWd1cmVfb3V0cHV0X2RpcmVjdG9yeSwgIlN1cHBsZW1lbnRhcnlfRmlndXJlN19fTUx0cmVlK3JhYmJpdHBhc3NhZ2VfMDItMjAyMS5zdmciKSwgd2lkdGggPSAxMDAwLCBoZWlnaHQgPSA4MDAsdHlwZT0ic3ZnIix1bml0cyA9ICJwdCIpCnAucmFiYml0LnBhc3NhZ2UuZGlzdHJvcy5jb21iaW5hdGlvbgojZGV2Lm9mZigpCgpgYGAKCgoKCgpcClwKXApcCkxvb2sgYXQgZGlzdHJpYnV0aW9uIG9mIFNOUHMgb24gZ2Vub21lXAoKYGBge3J9CgoKV0dTLnNpdGUucG9zaXRpb25zIDwtIHJlYWQudGFibGUoV0dTLnNpdGUucG9zaXRpb25zLmZpbGUsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGLCBoZWFkZXI9RikKY29sbmFtZXMoV0dTLnNpdGUucG9zaXRpb25zKSA8LSAicG9zaXRpb24iCgpnZ3Bsb3QoV0dTLnNpdGUucG9zaXRpb25zLCBhZXMocG9zaXRpb24pKSArIAogIGdlb21fZGVuc2l0eSgpICsKICB0aGVtZV9saWdodCgpCgpXR1Muc2l0ZS5wb3NpdGlvbnMkU05QIDwtIDEKV0dTLnNpdGUucG9zaXRpb25zLmFsbCA8LSBwbHlyOjpqb2luKFdHUy5zaXRlLnBvc2l0aW9ucywgZGF0YS5mcmFtZShwb3NpdGlvbj1jKDE6MTEzOTU2OSksc3RyaW5nc0FzRmFjdG9ycz1GKSwgdHlwZT0icmlnaHQiLCBieT0icG9zaXRpb24iKQpXR1Muc2l0ZS5wb3NpdGlvbnMuYWxsW2lzLm5hKFdHUy5zaXRlLnBvc2l0aW9ucy5hbGwkU05QKSwiU05QIl0gPC0gMAoKCndpbmRvd3NpemUgPC0gMTAwMApXR1Muc2l0ZS5wb3NpdGlvbnMuYWxsJHdpbmRvdyA8LSAoKHRydW5jKGFzLm51bWVyaWMoV0dTLnNpdGUucG9zaXRpb25zLmFsbCRwb3NpdGlvbikgLyB3aW5kb3dzaXplLDApKSp3aW5kb3dzaXplKQpXR1MuU05QLmRlbnNpdHkud2luZG93IDwtIFdHUy5zaXRlLnBvc2l0aW9ucy5hbGwgJT4lIAogIGdyb3VwX2J5KHdpbmRvdykgJT4lIAogIGRwbHlyOjpzdW1tYXJpc2UobWVhbiA9IG1lYW4oU05QKSwgY291bnQ9c3VtKFNOUCkpCgpwLldHUy5TTlAuZGVuc2l0eSA8LSBnZ3Bsb3QoV0dTLlNOUC5kZW5zaXR5LndpbmRvdywgYWVzKHdpbmRvdywgY291bnQpKSArIAogIGdlb21fcG9pbnQoYWxwaGE9MC41KSArCiAgdGhlbWVfbGlnaHQoKSArIAogIGxhYnMoeD1wYXN0ZTAoIkdlbm9tZSBQb3NpdGlvbiAoIix3aW5kb3dzaXplLCIgYnAgd2luZG93cykiKSwgeT1wYXN0ZTAoIlZhcmlhYmxlIHNpdGVzLyIsd2luZG93c2l6ZSwiIGJwIikpICsKICB0aGVtZS50ZXh0LnNpemUKcC5XR1MuU05QLmRlbnNpdHkKCgoKCmBgYAoKCgojIEJyaW5nIG1hY3JvbGlkZSByZXNpc3RhbmNlIGJhY2sgaW4KCkxvb2sgYXQgbWFjcm9saWRlIHJlc2lzdGFuY2UKYGBge3J9CgoKVFBBLmdsb2JhbC5jb21wbWFwcGluZy4yM3MgPC0gcmVhZC50YWJsZShUUEEuZ2xvYmFsLmNvbXBtYXBwaW5nLjIzcy5maWxlLCBoZWFkZXI9VCwgc2VwPSJcdCIsIGNoZWNrLm5hbWVzID0gRiwgY29tbWVudC5jaGFyID0gIiIpCgoKIyBNaXNzaW5nIHRyZWUgc2FtcGxlcyBmcm9tIDIzcyBkYXRhCm1pc3NpbmcuMjNTIDwtIFRQQS5NTHRyZWUkdGlwLmxhYmVsW1RQQS5NTHRyZWUkdGlwLmxhYmVsICVub3RpbiUgVFBBLmdsb2JhbC5jb21wbWFwcGluZy4yM3MkU2FtcGxlXSAKbWlzc2luZy4yM1MubWV0YSA8LSBUUEEubWV0YTEuMi5waW5lY29uZVtUUEEubWV0YTEuMi5waW5lY29uZSRTYW1wbGVfTmFtZSAlaW4lIG1pc3NpbmcuMjNTLCAiQ2xlYW5lZF9mYXN0cV9pZCJdCgojIE9ubHkga2VlcCByZWxldmFudCB2YWx1ZXMKVFBBLmdsb2JhbC5jb21wbWFwcGluZy4yM3MgPC0gVFBBLmdsb2JhbC5jb21wbWFwcGluZy4yM3NbVFBBLmdsb2JhbC5jb21wbWFwcGluZy4yM3MkU2FtcGxlICVpbiUgVFBBLk1MdHJlZSR0aXAubGFiZWwsXQoKClRQQS5nbG9iYWwuY29tcG1hcHBpbmcuMjNzJFNhbXBsZV9OYW1lIDwtIFRQQS5nbG9iYWwuY29tcG1hcHBpbmcuMjNzJFNhbXBsZQoKIyBFdmFsdWF0ZSBhbGxlbGVzIChhZ2FpbikKVFBBLmdsb2JhbC5jb21wbWFwcGluZy4yM3MkVmFyaWFudFByZXNlbnRfQTIwNThHX3JlZG8gPC0gaWZlbHNlKChUUEEuZ2xvYmFsLmNvbXBtYXBwaW5nLjIzcyRBTFRfQTIwNThHPT0iRyIgJiBUUEEuZ2xvYmFsLmNvbXBtYXBwaW5nLjIzcyREUF9BMjA1OEc+MjAgJiBUUEEuZ2xvYmFsLmNvbXBtYXBwaW5nLjIzcyRBbHRQZXJjX0EyMDU4Rz45NSksIlllcyIsIGlmZWxzZShUUEEuZ2xvYmFsLmNvbXBtYXBwaW5nLjIzcyRWYXJpYW50UHJlc2VudF9BMjA1OEc9PSJIZXRlcm8iLCJVbmNlcnRhaW4iLGlmZWxzZSgoVFBBLmdsb2JhbC5jb21wbWFwcGluZy4yM3MkQUxUX0EyMDU4Rz09IkciICYgVFBBLmdsb2JhbC5jb21wbWFwcGluZy4yM3MkRFBfQTIwNThHPD0yMCAmIFRQQS5nbG9iYWwuY29tcG1hcHBpbmcuMjNzJEFsdFBlcmNfQTIwNThHPjk1KSwiVW5jZXJ0YWluIiwiTm8iKSkpCgpUUEEuZ2xvYmFsLmNvbXBtYXBwaW5nLjIzcyRWYXJpYW50UHJlc2VudF9BMjA1OUdfcmVkbyA8LSBpZmVsc2UoKFRQQS5nbG9iYWwuY29tcG1hcHBpbmcuMjNzJEFMVF9BMjA1OUc9PSJHIiAmIFRQQS5nbG9iYWwuY29tcG1hcHBpbmcuMjNzJERQX0EyMDU5Rz4yMCAmIFRQQS5nbG9iYWwuY29tcG1hcHBpbmcuMjNzJEFsdFBlcmNfQTIwNTlHPjk1KSwiWWVzIiwgaWZlbHNlKFRQQS5nbG9iYWwuY29tcG1hcHBpbmcuMjNzJFZhcmlhbnRQcmVzZW50X0EyMDU5Rz09IkhldGVybyIsIlVuY2VydGFpbiIsaWZlbHNlKChUUEEuZ2xvYmFsLmNvbXBtYXBwaW5nLjIzcyRBTFRfQTIwNTlHPT0iRyIgJiBUUEEuZ2xvYmFsLmNvbXBtYXBwaW5nLjIzcyREUF9BMjA1OUc8PTIwICYgVFBBLmdsb2JhbC5jb21wbWFwcGluZy4yM3MkQWx0UGVyY19BMjA1OEc+OTUpLCJVbmNlcnRhaW4iLCJObyIpKSkKCgpUUEEuZ2xvYmFsLmNvbXBtYXBwaW5nLjIzcyRyZXNpc3RhbnQgPC0gaWZlbHNlKChUUEEuZ2xvYmFsLmNvbXBtYXBwaW5nLjIzcyRWYXJpYW50UHJlc2VudF9BMjA1OEdfcmVkbz09IkhldGVybyIgfCBUUEEuZ2xvYmFsLmNvbXBtYXBwaW5nLjIzcyRWYXJpYW50UHJlc2VudF9BMjA1OUdfcmVkbz09IlVuY2VydGFpbiIpLCJVbmNlcnRhaW4iLGlmZWxzZShUUEEuZ2xvYmFsLmNvbXBtYXBwaW5nLjIzcyRWYXJpYW50UHJlc2VudF9BMjA1OEdfcmVkbz09IlllcyIgJiBUUEEuZ2xvYmFsLmNvbXBtYXBwaW5nLjIzcyRWYXJpYW50UHJlc2VudF9BMjA1OUdfcmVkbz09Ik5vIiwgIkEyMDU4RyIsIGlmZWxzZShUUEEuZ2xvYmFsLmNvbXBtYXBwaW5nLjIzcyRWYXJpYW50UHJlc2VudF9BMjA1OEdfcmVkbz09Ik5vIiAmIFRQQS5nbG9iYWwuY29tcG1hcHBpbmcuMjNzJFZhcmlhbnRQcmVzZW50X0EyMDU5R19yZWRvPT0iWWVzIiwiQTIwNTlHIiwgaWZlbHNlKFRQQS5nbG9iYWwuY29tcG1hcHBpbmcuMjNzJFZhcmlhbnRQcmVzZW50X0EyMDU4R19yZWRvPT0iTm8iICYgVFBBLmdsb2JhbC5jb21wbWFwcGluZy4yM3MkVmFyaWFudFByZXNlbnRfQTIwNTlHX3JlZG89PSJObyIsICJTZW5zaXRpdmUiLCJVbmNlcnRhaW4iKSkpKQoKYGBgCgpOb3cgcGxvdCBpbiBhIG5pY2UgdHJlZQpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9OCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KClRQQS5nbG9iYWwuY29tcG1hcHBpbmcuMjNzLnAgPC0gZGF0YS5mcmFtZShyb3cubmFtZXM9VFBBLmdsb2JhbC5jb21wbWFwcGluZy4yM3MkU2FtcGxlLCBBMjA1OEc9VFBBLmdsb2JhbC5jb21wbWFwcGluZy4yM3MkVmFyaWFudFByZXNlbnRfQTIwNThHX3JlZG8sIEEyMDU5Rz1UUEEuZ2xvYmFsLmNvbXBtYXBwaW5nLjIzcyRWYXJpYW50UHJlc2VudF9BMjA1OUdfcmVkbykKCnAuTUx0cmVlLjIzUy5kaXN0cm9zIDwtIGdoZWF0bWFwKFRQQS5NTHRyZWUuZ2d0cmVlLnRpcHBvaW50ICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiksCiAgICAgICAgICAgICAgIFRQQS5nbG9iYWwuY29tcG1hcHBpbmcuMjNzLnAsIGNvbG9yPSdncmV5NzAnLHdpZHRoPTAuMDc1LG9mZnNldD0wLjAwMDAwNzI1LCBjb2xuYW1lc19hbmdsZT0tNDUsY29sbmFtZXNfb2Zmc2V0X3k9MCwgaGp1c3Q9MCxmb250LnNpemU9MikgKyAKICAjc2NhbGVfZmlsbF9tYW51YWwobmFtZT0iUmVzaXN0YW5jZVxuQWxsZWxlXG5QcmVzZW50Iix2YWx1ZXM9YygiZ3JleTUwIiwiZ3JleTk1IiwiYmxhY2siKSwgYnJlYWtzPWMoIlVuY2VydGFpbiIsIk5vIiwiWWVzIikpICsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lPSJSZXNpc3RhbmNlXG5BbGxlbGVcblByZXNlbnQiLHZhbHVlcz1jKCJibGFjayIsImdyZXk5NSIsImdyZXk1MCIpLCBicmVha3M9YygiWWVzIiwiTm8iLCJVbmNlcnRhaW4iKSkgKwogIHRoZW1lLnRleHQuc2l6ZSArIHRoZW1lKGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC42NSwibGluZSIpLGxlZ2VuZC5wb3NpdGlvbj0nbGVmdCcpCgpwLk1MdHJlZS4yM1MuZGlzdHJvcwpgYGAKCgoKCkxvb2sgYXQgc3VibGluZWFnZSBkaXN0cmlidXRpb24KYGBge3IsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTYsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9ClRQQS5tZXRhMS4yLnBpbmVjb25lLjIzUyA8LSBwbHlyOjpqb2luKFRQQS5tZXRhMS4yLnBpbmVjb25lLGRhdGEuZnJhbWUoU2FtcGxlX05hbWU9VFBBLmdsb2JhbC5jb21wbWFwcGluZy4yM3MkU2FtcGxlLCBBMjA1OEc9VFBBLmdsb2JhbC5jb21wbWFwcGluZy4yM3MkVmFyaWFudFByZXNlbnRfQTIwNThHX3JlZG8sIEEyMDU5Rz1UUEEuZ2xvYmFsLmNvbXBtYXBwaW5nLjIzcyRWYXJpYW50UHJlc2VudF9BMjA1OUdfcmVkbyksIGJ5PSJTYW1wbGVfTmFtZSIpCgoKVFBBLm1ldGExLjIucGluZWNvbmUuMjNTLmNvdW50cyA8LSBkYXRhLmZyYW1lKFRQQS5tZXRhMS4yLnBpbmVjb25lLjIzUyAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRwbHlyOjpncm91cF9ieShUUEEucGluZWNvbmUuc3VibGluZWFnZSwgQTIwNThHLCBBMjA1OUcpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcGx5cjo6c3VtbWFyaXNlKENvdW50PW4oKSksc3RyaW5nc0FzRmFjdG9ycyA9IEYpClRQQS5tZXRhMS4yLnBpbmVjb25lLjIzUy5jb3VudHMgPC0gcmVzaGFwZTI6Om1lbHQoVFBBLm1ldGExLjIucGluZWNvbmUuMjNTLmNvdW50cyxpZC52YXJzPWMoIlRQQS5waW5lY29uZS5zdWJsaW5lYWdlIiwiQ291bnQiKSkKCgpUUEEubWV0YTEuMi5waW5lY29uZS4yM1MuY291bnRzJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlIDwtIGZhY3RvcihUUEEubWV0YTEuMi5waW5lY29uZS4yM1MuY291bnRzJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlLCBsZXZlbHM9cmV2KHN1YmxpbmVhZ2VzLmNvbHMuYnJldyRzdWJsaW5lYWdlKSkKCiNUUEEubWV0YTEuMi5waW5lY29uZS4yM1MuY291bnRzIDwtIFRQQS5tZXRhMS4yLnBpbmVjb25lLjIzUy5jb3VudHNbVFBBLm1ldGExLjIucGluZWNvbmUuMjNTLmNvdW50cyRUUEEucGluZWNvbmUuc3VibGluZWFnZSE9IlNpbmdsZXRvbiIsXQoKVFBBLm1ldGExLjIucGluZWNvbmUuMjNTLmNvdW50cyR2YWx1ZSA8LSBpZmVsc2UoVFBBLm1ldGExLjIucGluZWNvbmUuMjNTLmNvdW50cyR2YWx1ZT09IkhldGVybyIsICJVbmNlcnRhaW4iLFRQQS5tZXRhMS4yLnBpbmVjb25lLjIzUy5jb3VudHMkdmFsdWUpCgojIFBsb3QgU05QcyBieSBzdWJsaW5lYWdlCnAuc3VibGluZWFnZS4yM1MuY29tcG1hcCA8LSBnZ3Bsb3QoVFBBLm1ldGExLjIucGluZWNvbmUuMjNTLmNvdW50cywgYWVzKENvdW50LCBUUEEucGluZWNvbmUuc3VibGluZWFnZSwgZmlsbD12YWx1ZSwgY29sb3I9TlVMTCkpICsKICBnZW9tX2Jhcmgoc3RhdD0iaWRlbnRpdHkiLCBwb3NpdGlvbj0iZmlsbCIsd2lkdGg9MC43NSkgKyAKICBmYWNldF9ncmlkKC5+dmFyaWFibGUpICsgCiAgdGhlbWVfbGlnaHQoKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoImJsYWNrIiwiZ3JleTkwIiwiZ3JleTUwIiksIGJyZWFrcz1jKCJZZXMiLCJObyIsIlVuY2VydGFpbiIpKSArCiAgdGhlbWUoc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvcj0nd2hpdGUnLCBmaWxsPSd3aGl0ZScsbGluZXR5cGU9InNvbGlkIiksIHN0cmlwLnRleHQueD1lbGVtZW50X3RleHQoY29sb3IgPSAiZ3JleTI1IixhbmdsZT0wLCBzaXplPTEwKSkgKwogIGxhYnMoeD0iUHJvcG9ydGlvbiBvZiBzYW1wbGVzIix5PSJTdWJsaW5lYWdlIiwgZmlsbD0iUmVzaXN0YW5jZVxuYWxsZWxlXG5wcmVzZW50IikgKwogIHRoZW1lLnRleHQuc2l6ZSArIHRoZW1lKGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC43NSwibGluZSIpLGxlZ2VuZC5wb3NpdGlvbj0nYm90dG9tJykgCiNwLnN1YmxpbmVhZ2UuMjNTLmNvbXBtYXAKCgoKIyBXYW50IHRvIGluY2x1ZGUgU2luZ2xldG9ucyBmb3IgdGhpcyBhbmFseWlzICAtIFJlZG8gY291bnRyeSBzdWJsaW5lYWdlIGRpc3Ryb3MKc3VibGluZWFnZS5jb3VudHJ5LmNvdW50cy5pbmNTaW5nIDwtIHBseXI6OmpvaW4oVFBBLm1ldGExLjIucGluZWNvbmVbKFRQQS5tZXRhMS4yLnBpbmVjb25lJFNhbXBsZV9ZZWFyIT0iLSIpLGMoIlNhbXBsZV9OYW1lIiwiVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UiKV0sIHN1YmxpbmVhZ2UuY2xhc3NpZmljYXRpb24sIGJ5PSJUUEEucGluZWNvbmUuc3VibGluZWFnZSIsdHlwZT0ibGVmdCIpCnN1YmxpbmVhZ2UuY291bnRyeS5jb3VudHMuaW5jU2luZ1tpcy5uYShzdWJsaW5lYWdlLmNvdW50cnkuY291bnRzLmluY1NpbmckcHJpdmF0ZS5kaXN0cm8pLCJwcml2YXRlLmRpc3RybyJdIDwtICJTaW5nbGV0b24iCnN1YmxpbmVhZ2UuY291bnRyeS5jb3VudHMuaW5jU2luZyA8LSBzdWJsaW5lYWdlLmNvdW50cnkuY291bnRzLmluY1NpbmcgJT4lIGdyb3VwX2J5KFRQQS5waW5lY29uZS5zdWJsaW5lYWdlLCBwcml2YXRlLmRpc3RybykgJT4lIHN1bW1hcmlzZShDb3VudD1uKCkpCnN1YmxpbmVhZ2UuY291bnRyeS5jb3VudHMuaW5jU2luZyRUUEEucGluZWNvbmUuc3VibGluZWFnZSA8LSBmYWN0b3Ioc3VibGluZWFnZS5jb3VudHJ5LmNvdW50cy5pbmNTaW5nJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlLGxldmVscz1yZXYoc3VibGluZWFnZXMuY29scy5icmV3JHN1YmxpbmVhZ2UpKQoKcC5zdWJsaW5lYWdlLnByaXZhdGUuaGJhcnBsb3QuaW5jU2luZyA8LSBnZ3Bsb3Qoc3VibGluZWFnZS5jb3VudHJ5LmNvdW50cy5pbmNTaW5nLCBhZXMoQ291bnQsVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UsZmlsbD1wcml2YXRlLmRpc3RybykpICsKICBnZW9tX2Jhcmgoc3RhdD0iaWRlbnRpdHkiLCBwb3NpdGlvbj0ic3RhY2siLCB3aWR0aD0wLjc1KSArCiAgdGhlbWVfbGlnaHQoKSArCiAgI3NjYWxlX3hfbG9nMTAoKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW09YygwLDQxMCkpICsKICB0aGVtZS50ZXh0LnNpemUgKyB0aGVtZShsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNjUsImxpbmUiKSxsZWdlbmQucG9zaXRpb249J2JvdHRvbScpICsKICBzY2FsZV9maWxsX21hbnVhbChicmVha3M9KHVuaXF1ZShzdWJsaW5lYWdlLmNvdW50cnkuY291bnRzLmluY1NpbmckcHJpdmF0ZS5kaXN0cm8pKSwgdmFsdWVzPXJldihjKCJncmV5ODAiLCJncmV5NTAiLCJncmV5MTAiKSkpICsKICBsYWJzKHk9IlN1YmxpbmVhZ2UiLCB4PSJTYW1wbGUgQ291bnQiLCBmaWxsPSJTdWJsaW5lYWdlXG5UeXBlIikgKwogIGdlb21fdGV4dChkYXRhPXN1YmxpbmVhZ2UuY291bnRyeS5jb3VudHMuaW5jU2luZywgYWVzKChDb3VudCsyMCksIFRQQS5waW5lY29uZS5zdWJsaW5lYWdlLGxhYmVsPUNvdW50KSwgc2l6ZT0yLjUsIGluaGVyaXQuYWVzID0gRikKI3Auc3VibGluZWFnZS5wcml2YXRlLmhiYXJwbG90LmluY1NpbmcKCgojcGxvdF9ncmlkKHAuc3VibGluZWFnZS5oYmFycGxvdCwgcC5zdWJsaW5lYWdlLjIzUy5jb21wbWFwICsgeS50aGVtZS5zdHJpcCwgYWxpZ249J2gnLCBheGlzPSd0YicsIHJlbF93aWR0aHMgPWMoMSwyKSkKcC5zdWJsaW5lYWdlLjIzUy5jb21wbWFwLmRpc3RyaWJ1dGlvbnMgPC0gcGxvdF9ncmlkKHAuc3VibGluZWFnZS5wcml2YXRlLmhiYXJwbG90LmluY1NpbmcsIHAuc3VibGluZWFnZS4yM1MuY29tcG1hcCArIHkudGhlbWUuc3RyaXAsIGFsaWduPSdoJywgYXhpcz0ndGInLCByZWxfd2lkdGhzID1jKDEsMSkpCgoKcC5zdWJsaW5lYWdlLjIzUy5jb21wbWFwLmRpc3RyaWJ1dGlvbnMKYGBgCgpQbG90IGRpc3Ryb3Mgd2l0aCB0cmVlCgpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9MTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBsb3QuTUx0cmVlLjIzcy53aXRoLnN1YmxpbmVhZ2UuZGlzdHJvcy5jb21ibyA8LSBwbG90X2dyaWQocC5NTHRyZWUuMjNTLmRpc3Ryb3MsIHAuc3VibGluZWFnZS4yM1MuY29tcG1hcC5kaXN0cmlidXRpb25zLCBuY29sPTEsIHJlbF9oZWlnaHRzPWMoMywyKSwgbGFiZWxzPWMoJ0EnLCdCJyksIGxhYmVsX3NpemU9MTEpCgojQ2Fpcm86OkNhaXJvKGZpbGU9cGFzdGUwKEZpZ3VyZV9vdXRwdXRfZGlyZWN0b3J5LCAiU3VwcGxlbWVudGFyeV9GaWd1cmUxNF9TdWJsaW5lYWdlX3ZzX21hY3JvbGlkZS1kaXN0cm9zX18wMi0yMDIxLnN2ZyIpLCB3aWR0aCA9IDgwMCwgaGVpZ2h0ID0gMTAwMCx0eXBlPSJzdmciLHVuaXRzID0gInB0IikKcGxvdC5NTHRyZWUuMjNzLndpdGguc3VibGluZWFnZS5kaXN0cm9zLmNvbWJvCiNkZXYub2ZmKCkKYGBgCgoKCgoKCkxvb2sgYXQgdGVtcG9yYWwgZGlzdHJpYnV0aW9uIG9mIHNhbXBsZXMKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD04LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKClRQQS5tZXRhMS4yLnBpbmVjb25lLjIzcy5zaW1wbGVkYXRlcyA8LSBwbHlyOjpqb2luKFRQQS5tZXRhMS4yLnBpbmVjb25lWyxjKCJTYW1wbGVfTmFtZSIsIlRQQS5waW5lY29uZS5zdWJsaW5lYWdlIiwiU2FtcGxlX1llYXIiKV0sVFBBLmdsb2JhbC5jb21wbWFwcGluZy4yM3MsIGJ5PSJTYW1wbGVfTmFtZSIpCgpUUEEubWV0YTEuMi5waW5lY29uZS4yM3Muc2ltcGxlZGF0ZXMgPC0gZGF0YS5mcmFtZShUUEEubWV0YTEuMi5waW5lY29uZS4yM3Muc2ltcGxlZGF0ZXMgJT4lIGdyb3VwX2J5KHJlc2lzdGFudCxUUEEucGluZWNvbmUuc3VibGluZWFnZSxTYW1wbGVfWWVhcikgJT4lCiAgc3VtbWFyaXNlKENvdW50PW4oKSksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQoKClRQQS5tZXRhMS4yLnBpbmVjb25lLjIzcy5zaW1wbGVkYXRlcyA8LSBUUEEubWV0YTEuMi5waW5lY29uZS4yM3Muc2ltcGxlZGF0ZXNbVFBBLm1ldGExLjIucGluZWNvbmUuMjNzLnNpbXBsZWRhdGVzJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlIT0iU2luZ2xldG9uIixdCgpUUEEubWV0YTEuMi5waW5lY29uZS4yM3Muc2ltcGxlZGF0ZXMgPC0gcGx5cjo6am9pbihkYXRhLmZyYW1lKFNhbXBsZV9ZZWFyPWMoMTkxMjoyMDE5KSxzdHJpbmdzQXNGYWN0b3JzPUYpLCBUUEEubWV0YTEuMi5waW5lY29uZS4yM3Muc2ltcGxlZGF0ZXMpClRQQS5tZXRhMS4yLnBpbmVjb25lLjIzcy5zaW1wbGVkYXRlcyA8LSBUUEEubWV0YTEuMi5waW5lY29uZS4yM3Muc2ltcGxlZGF0ZXNbIWlzLm5hKFRQQS5tZXRhMS4yLnBpbmVjb25lLjIzcy5zaW1wbGVkYXRlcyRUUEEucGluZWNvbmUuc3VibGluZWFnZSksXQpUUEEubWV0YTEuMi5waW5lY29uZS4yM3Muc2ltcGxlZGF0ZXMgPC0gVFBBLm1ldGExLjIucGluZWNvbmUuMjNzLnNpbXBsZWRhdGVzWyFpcy5uYShUUEEubWV0YTEuMi5waW5lY29uZS4yM3Muc2ltcGxlZGF0ZXMkcmVzaXN0YW50KSxdCgoKClRQQS5tZXRhMS4yLnBpbmVjb25lLjIzcy5zaW1wbGVkYXRlcyRUUEEucGluZWNvbmUuc3VibGluZWFnZSA8LSBmYWN0b3IoVFBBLm1ldGExLjIucGluZWNvbmUuMjNzLnNpbXBsZWRhdGVzJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlLCBsZXZlbHM9KHN1YmxpbmVhZ2VzLmNvbHMuYnJldyRzdWJsaW5lYWdlKSkKCgojZ2dwbG90KFRQQS5tZXRhMS4yLnBpbmVjb25lLjIzcy5zaW1wbGVkYXRlcywgYWVzKFNhbXBsZV9ZZWFyLCBUUEEucGluZWNvbmUuc3VibGluZWFnZSwgY29sb3I9cmVzaXN0YW50LCBzaXplPUNvdW50KSkgKwojICBnZW9tX3BvaW50KCkKCiNnZ3Bsb3QoVFBBLm1ldGExLjIucGluZWNvbmUuMjNzLnNpbXBsZWRhdGVzLCBhZXMoU2FtcGxlX1llYXIsIFRQQS5waW5lY29uZS5zdWJsaW5lYWdlLCBjb2xvcj1yZXNpc3RhbnQsIHNpemU9Q291bnQpKSArCiMgIGdlb21faml0dGVyKCkKCgpwLmJ1YmJsZXBsb3Quc3VibGluZWFnZS5yZXNpc3RhbmNlLmFsbGVsZXMgPC0gZ2dwbG90KFRQQS5tZXRhMS4yLnBpbmVjb25lLjIzcy5zaW1wbGVkYXRlcywgYWVzKFNhbXBsZV9ZZWFyLCByZXNpc3RhbnQsIGNvbG9yPXJlc2lzdGFudCkpICsKICBnZW9tX3BvaW50KGFscGhhPTAuNjUsIGFlcyhzaXplPUNvdW50KSkgKyAKICB0aGVtZV9saWdodCgpICsKICBmYWNldF93cmFwKFRQQS5waW5lY29uZS5zdWJsaW5lYWdlfi4pICsKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbT1jKDE5NzAsMjAyMCkpICsgCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1zZXEoMTk3MCwyMDIwLDIwKSkgKwogIHNjYWxlX3NpemVfYXJlYShtYXhfc2l6ZSA9IDgsYnJlYWtzPWMoMSw1LDEwLDI1LDUwLDc1LDEwMCkpICsKICB0aGVtZShzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG9yPSd3aGl0ZScsIGZpbGw9J3doaXRlJyxsaW5ldHlwZT0ic29saWQiKSwgc3RyaXAudGV4dC54PWVsZW1lbnRfdGV4dChjb2xvciA9ICJncmV5MjUiLGFuZ2xlPTAsIHNpemU9MTApKSArCiAgdGhlbWUudGV4dC5zaXplICsgdGhlbWUobGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjc1LCJsaW5lIiksbGVnZW5kLnBvc2l0aW9uPSd0b3AnKSArCiAgI3NjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiYmxhY2siLCJibGFjayIsImdyZXk5MCIsImdyZXk1MCIpLCBicmVha3M9YygiQTIwNThHIiwiQTIwNTlHIiwiU2Vuc2l0aXZlIiwiVW5jZXJ0YWluIikpCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWU9IlJlc2lzdGFuY2VcbkFsbGVsZSIsIHZhbHVlcz1jKCJyZWQiLCJibHVlIiwiYmxhY2siLCJncmV5NzUiKSwgYnJlYWtzPWMoIkEyMDU4RyIsIkEyMDU5RyIsIlNlbnNpdGl2ZSIsIlVuY2VydGFpbiIpKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMjAwMCwgY29sb3I9J2JsdWUnLCBhbHBoYT0wLjI1KSArCiAgbGFicyh4PSJTYW1wbGUgWWVhciIsIHk9IlJlc2lzdGFuY2UgQWxsZWxlIikKICAKcC5idWJibGVwbG90LnN1YmxpbmVhZ2UucmVzaXN0YW5jZS5hbGxlbGVzCgoKCmBgYAoKIyBMb29rIGF0IGdlbmV0aWMgZGlzdGFuY2Ugdi5zLiBnZW9ncmFwaGljIGRpc3RhbmNlIChuZWVkIHRvIGluZmVyIGdlb2dyYXBoaWMgZGlzdGFuY2VzIGJldHdlZW4gc2FtcGxlcykKIyMjIFNpbmNlIHNwZWNpZmljIHdpdGhpbi1jb3VudHJ5IGdwcyBkYXRhIGlzIGxpbWl0ZWQgb3IgdW5hdmFpbGFibGUsIHdpbGwgaW5mZXIgZ2VvZ3JhcGhpYyBkaXN0YW5jZSBiZXR3ZWVuIGNvdW50cnkgY2VudHJvaWRzIChhbHJlYWR5IGluZmVycmVkIGFib3ZlIGZvciBtYXApIC0gY3J1ZGUgYnV0IG1heSBwcm92aWRlIHNvbWUgaW5zaWdodHMuIApQbG90IHRvZ2V0aGVyCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9OCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhMiA8LSBwbHlyOjpqb2luKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YSxkYXRhLmZyYW1lKEdlb19Db3VudHJ5LnQxPWNvdW50cnkuY29vcmRzLnN1YnNldCRHZW9fQ291bnRyeSwgTG9uZzE9Y291bnRyeS5jb29yZHMuc3Vic2V0JGNlbnRyb2lkLmxvbiwgTGF0MT1jb3VudHJ5LmNvb3Jkcy5zdWJzZXQkY2VudHJvaWQubGF0LCBzdHJpbmdzQXNGYWN0b3JzID0gRiksIHR5cGU9ImxlZnQiLCBieT0iR2VvX0NvdW50cnkudDEiKQpUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEyIDwtIHBseXI6OmpvaW4oVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhMixkYXRhLmZyYW1lKEdlb19Db3VudHJ5LnQyPWNvdW50cnkuY29vcmRzLnN1YnNldCRHZW9fQ291bnRyeSwgTG9uZzI9Y291bnRyeS5jb29yZHMuc3Vic2V0JGNlbnRyb2lkLmxvbiwgTGF0Mj1jb3VudHJ5LmNvb3Jkcy5zdWJzZXQkY2VudHJvaWQubGF0LCBzdHJpbmdzQXNGYWN0b3JzID0gRiksIHR5cGU9ImxlZnQiLCBieT0iR2VvX0NvdW50cnkudDIiKQoKIyBVc2UgZ2Vvc3BoZXJlIHBhY2thZ2UgKGRpc3RWaW5jZW50eUVsbGlwc29pZCkgdG8gY2FsY3VsYXRlIGdlb2dyYXBoaWMgZGlzdGFuY2UgYmV0d2VlbiBwb2ludHMgaW4ga20KVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhMiRHZW9ncmFwaGljLkRpc3RhbmNlIDwtIGdlb3NwaGVyZTo6ZGlzdFZpbmNlbnR5RWxsaXBzb2lkKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YTJbLGMoIkxvbmcxIiwiTGF0MSIpXSxUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEyWyxjKCJMb25nMiIsIkxhdDIiKV0pLzEwMDAKCmBgYAoKCk5vdyBwbG90CmBgYHtyfQojIEdlbmV0aWMgRGlzdGFuY2Ugdi5zLiBHZW9ncmFwaGljIERpc3RhbmNlIChzYW1lIExpbmVhZ2VzKQpwLmdlb2dyYXBoaWMudnMuZ2VuZXRpYy5kaXN0YW5jZS5oZXguTGluZWFnZSA8LSBnZ3Bsb3QoVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhMltUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEyJHNhbWUuVFBBLm1ham9ybGluZWFnZT09InNhbWUiLF0sIGFlcyhHZW9ncmFwaGljLkRpc3RhbmNlLERpc3RhbmNlKSkgKwojZ2dwbG90KFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YTIsIGFlcyhHZW9ncmFwaGljLkRpc3RhbmNlLERpc3RhbmNlKSkgKyAKICBzdGF0X2Jpbl9oZXgoY29sb3VyPSJ3aGl0ZSIsIG5hLnJtPVRSVUUsIGJpbnMgPSAyMCkgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG91cnM9YygicHVycGxlIiwiZ3JlZW4iKSwgCiAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJDb21wYXJpc29uIEZyZXF1ZW5jeSIsIGJyZWFrcz1jKDMsMTAwLDMwMDApLAogICAgICAgICAgICAgICAgICAgICAgIG5hLnZhbHVlPU5BLCB0cmFucz0ibG9nMTAiKSArIAogIHRoZW1lX2xpZ2h0KCkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKDAsMjUwLDEwKSkgKwogIGxhYnMoeT0iUGFpcndpc2UgZ2VuZXRpYyBkaXN0YW5jZSAoU05QcykiLCB4PSJQYWlyd2lzZSBnZW9ncmFwaGljIGRpc3RhbmNlIChraWxvbWV0ZXJzKSIpICsKICB0aGVtZS50ZXh0LnNpemUgKyB0aGVtZShsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNzUsImxpbmUiKSkgKwogIHRoZW1lKHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0nd2hpdGUnLGxpbmV0eXBlPSJzb2xpZCIpLCBzdHJpcC50ZXh0Lng9ZWxlbWVudF90ZXh0KGNvbG9yPSJncmV5MjUiLCBzaXplPTEwKSwgc3RyaXAudGV4dC55PWVsZW1lbnRfdGV4dChjb2xvcj0iZ3JleTI1Iiwgc2l6ZT0xMCkpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIpICsKICAjZ2d0aXRsZSgiUGFpcndpc2UgU05QcyAoc2FtZSBzdWJsaW5lYWdlKSBhbmQgWWVhcnMgd2l0aGluIGFuZCBiZXR3ZWVuIEJyaXRpc2ggQ29sdW1iaWEgKENhbmFkYSkgYW5kIEVuZ2xhbmQgKFVLKSIpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKSArCiAgI2ZhY2V0X2dyaWQoVFBBX0xpbmVhZ2UudDF+c2FtZS5jb250aW5lbnQpICsKICAjZmFjZXRfZ3JpZCgufnNhbWUuY29udGluZW50KSArCiAgZmFjZXRfZ3JpZCguflRQQV9MaW5lYWdlLnQxKSArCiAgTlVMTApwLmdlb2dyYXBoaWMudnMuZ2VuZXRpYy5kaXN0YW5jZS5oZXguTGluZWFnZSA8LSBwLmdlb2dyYXBoaWMudnMuZ2VuZXRpYy5kaXN0YW5jZS5oZXguTGluZWFnZSArIHN0YXRfc21vb3RoKG1ldGhvZD0nbG0nLCBmdWxscmFuZ2U9RixzZT1ULCBjb2xvcj0nYmxhY2snLCBsZXZlbD05NSkKCnAuZ2VvZ3JhcGhpYy52cy5nZW5ldGljLmRpc3RhbmNlLmhleC5MaW5lYWdlCmBgYAoKQ2FsY3VsYXRlIFBlYXJzb24ncyBjb3JyZWxhdGlvbiAoZm9yIHJlYWwgZGF0YXNldCkKYGBge3J9CiMgRm9yIHdob2xlIGRhdGFzZXQgKGJ1dCBvbmx5IGxvb2tpbmcgd2l0aGluIHNhbWUgTGluZWFnZSkKcmVhbC5jb3JyZWxhdGlvbjEgPC0gY29yKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YTJbVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhMiRzYW1lLlRQQS5tYWpvcmxpbmVhZ2U9PSJzYW1lIiwiRGlzdGFuY2UiXSxUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEyW1RQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YTIkc2FtZS5UUEEubWFqb3JsaW5lYWdlPT0ic2FtZSIsIkdlb2dyYXBoaWMuRGlzdGFuY2UiXSkKcmVhbC5jb3JyZWxhdGlvbjEKbnJvdyhUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEyW1RQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YTIkc2FtZS5UUEEubWFqb3JsaW5lYWdlPT0ic2FtZSIsXSkKCgojIEV4cGxpY2l0bHkgQnkgTGluZWFnZQoKIyBOaWNob2xzCnJlYWwuY29ycmVsYXRpb24xLk5pY2hvbHMgPC0gY29yKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YTJbKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YTIkc2FtZS5UUEEubWFqb3JsaW5lYWdlPT0ic2FtZSIgJiBUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEyJFRQQV9MaW5lYWdlLnQxPT0iTmljaG9scyIpLCJEaXN0YW5jZSJdLFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YTJbKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YTIkc2FtZS5UUEEubWFqb3JsaW5lYWdlPT0ic2FtZSIgJiBUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEyJFRQQV9MaW5lYWdlLnQxPT0iTmljaG9scyIpLCJHZW9ncmFwaGljLkRpc3RhbmNlIl0pCnJlYWwuY29ycmVsYXRpb24xLk5pY2hvbHMKbnJvdyhUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEyWyhUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEyJHNhbWUuVFBBLm1ham9ybGluZWFnZT09InNhbWUiICYgVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhMiRUUEFfTGluZWFnZS50MT09Ik5pY2hvbHMiKSxdKQoKIyBTUzE0CnJlYWwuY29ycmVsYXRpb24xLlNTMTQgPC0gY29yKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YTJbKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YTIkc2FtZS5UUEEubWFqb3JsaW5lYWdlPT0ic2FtZSIgJiBUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEyJFRQQV9MaW5lYWdlLnQxPT0iU1MxNCIpLCJEaXN0YW5jZSJdLFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YTJbKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YTIkc2FtZS5UUEEubWFqb3JsaW5lYWdlPT0ic2FtZSIgJiBUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEyJFRQQV9MaW5lYWdlLnQxPT0iU1MxNCIpLCJHZW9ncmFwaGljLkRpc3RhbmNlIl0pCnJlYWwuY29ycmVsYXRpb24xLlNTMTQKbnJvdyhUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEyWyhUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEyJHNhbWUuVFBBLm1ham9ybGluZWFnZT09InNhbWUiICYgVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhMiRUUEFfTGluZWFnZS50MT09IlNTMTQiKSxdKQpgYGAKCgoKYGBge3J9CgojIERlZmluZSBmdW5jdGlvbiB0byBjYWxjdWxhdGUgY29ycmVsYXRpb25zCmNhbGN1bGF0ZS5nZW5ldGljLnZzLmdlb2dyYXBoaWMuZGlzdGFuY2UuY29ycmVsYXRpb24gPC0gZnVuY3Rpb24oaW5wdXQuZGlzdGFuY2VzKXsKICBzZXQuc2VlZCgxMjM0NSkKICBib290c3RyYXAuY291bnQgPC0gMTAwMAogIGJvb3RzdHJhcC5jb3JyZWxhdGlvbjEgPC0gTlVMTAogICMgQ29ycmVsYXRpb24gZm9yIHJlYWwgZGF0YXNldAogIHJlYWwuY29ycmVsYXRpb24xIDwtIGNvcihpbnB1dC5kaXN0YW5jZXNbLCJEaXN0YW5jZSJdLGlucHV0LmRpc3RhbmNlc1ssIkdlb2dyYXBoaWMuRGlzdGFuY2UiXSkKICAjIEdlbmVyYXRlIDEwMDAgYm9vdHN0cmFwcyBhbmQgdGVzdCBjb3JyZWxhdGlvbgogIGZvciAoYm9vdHN0cmFwIGluIDE6Ym9vdHN0cmFwLmNvdW50KXsgCiAgICBzYW1wbGUxIDwtIGRhdGEuZnJhbWUoRGlzdGFuY2U9c2FtcGxlKGlucHV0LmRpc3RhbmNlc1ssIkRpc3RhbmNlIl0pLCBHZW9ncmFwaGljLkRpc3RhbmNlPWlucHV0LmRpc3RhbmNlc1ssIkdlb2dyYXBoaWMuRGlzdGFuY2UiXSwgcmVwbGFjZT1UKQogICAgYm9vdHN0cmFwLmNvcnJlbGF0aW9uMSA8LSBjKGJvb3RzdHJhcC5jb3JyZWxhdGlvbjEsIGNvcihzYW1wbGUxWywxXSwgc2FtcGxlMVssMl0pKQogIH0KICBib290c3RyYXAuY29ycmVsYXRpb24xIDwtIGRhdGEuZnJhbWUoQ29ycmVsYXRpb249Ym9vdHN0cmFwLmNvcnJlbGF0aW9uMSwgdHlwZT0iQm9vdHN0cmFwIixzdHJpbmdzQXNGYWN0b3JzPUYpCiAgYm9vdHN0cmFwLmNvcnJlbGF0aW9uMSA8LSByYmluZChkYXRhLmZyYW1lKENvcnJlbGF0aW9uPXJlYWwuY29ycmVsYXRpb24xLCB0eXBlPSJSZWFsIiwgc3RyaW5nc0FzRmFjdG9ycz1GKSxib290c3RyYXAuY29ycmVsYXRpb24xKQogICMgQ2FsY3VsYXRlIFAgdmFsdWU6ICgxK3N1bShzID49IHMwKSkvKE4rMSkgLSBwdXQgaXQgdXAgYWdhaW5zdCBhbGwgcm93cyBmb3IgY29kaW5nIHNpbXBsaWNpdHksIGJ1dCBvbmx5IGFwcGxpZXMgdG8gUkVBTCBkYXRhLgogIGJvb3RzdHJhcC5jb3JyZWxhdGlvbjEkcHZhbCA8LSAoMStzdW0oYm9vdHN0cmFwLmNvcnJlbGF0aW9uMVtib290c3RyYXAuY29ycmVsYXRpb24xJHR5cGU9PSJCb290c3RyYXAiLCJDb3JyZWxhdGlvbiJdID49IGJvb3RzdHJhcC5jb3JyZWxhdGlvbjFbYm9vdHN0cmFwLmNvcnJlbGF0aW9uMSR0eXBlPT0iUmVhbCIsIkNvcnJlbGF0aW9uIl0pKS8obnJvdyhib290c3RyYXAuY29ycmVsYXRpb24xW2Jvb3RzdHJhcC5jb3JyZWxhdGlvbjEkdHlwZT09IkJvb3RzdHJhcCIsXSkgKzEpCiAgIyBBZGp1c3QgdG8gbWluaW11bSBzZW5zaXRpdml0eSBvZiBtZXRob2QgKGluIGNhc2Ugb2YgemVybykKICBib290c3RyYXAuY29ycmVsYXRpb24xJHB2YWwgPC0gaWZlbHNlKGJvb3RzdHJhcC5jb3JyZWxhdGlvbjEkcHZhbD09MCwgMS9ib290c3RyYXAuY291bnQsYm9vdHN0cmFwLmNvcnJlbGF0aW9uMSRwdmFsKQogIGJvb3RzdHJhcC5jb3JyZWxhdGlvbjFbYm9vdHN0cmFwLmNvcnJlbGF0aW9uMSR0eXBlPT0iQm9vdHN0cmFwIiwicHZhbCJdIDwtIE5BCiAgYm9vdHN0cmFwLmNvcnJlbGF0aW9uMSRDb3JyZWxhdGlvbjIgPC0gaWZlbHNlKGJvb3RzdHJhcC5jb3JyZWxhdGlvbjEkdHlwZT09IkJvb3RzdHJhcCIsTkEsIGJvb3RzdHJhcC5jb3JyZWxhdGlvbjEkQ29ycmVsYXRpb24pCiAgYm9vdHN0cmFwLmNvcnJlbGF0aW9uMSRkYXRhc2V0Lmxlbmd0aCA8LSBucm93KGlucHV0LmRpc3RhbmNlcykKICByZXR1cm4oYm9vdHN0cmFwLmNvcnJlbGF0aW9uMSkKfQoKI2NhbGN1bGF0ZS5nZW5ldGljLnZzLmdlb2dyYXBoaWMuZGlzdGFuY2UuY29ycmVsYXRpb24oaW5wdXQuZGlzdGFuY2VzLmRmKQpnZW4uZ2VvLmRpc3QuTGluZWFnZSA8LSBjYWxjdWxhdGUuZ2VuZXRpYy52cy5nZW9ncmFwaGljLmRpc3RhbmNlLmNvcnJlbGF0aW9uKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YTJbVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhMiRzYW1lLlRQQS5tYWpvcmxpbmVhZ2U9PSJzYW1lIixdKQoKZ2dwbG90KGdlbi5nZW8uZGlzdC5MaW5lYWdlLCBhZXModHlwZSwgQ29ycmVsYXRpb24sIGNvbG9yPXR5cGUpKSArIAogIGdlb21fYm94cGxvdCgpICsgCiAgdGhlbWVfbGlnaHQoKSArCiAgI3NjYWxlX3lfbG9nMTAoKSArCiMgIGdlb21fdGV4dChhZXModHlwZSwgeT0wLjAwMiwgbGFiZWw9cGFzdGUwKCJwPCIscm91bmQocHZhbFsxXSw1KSksIGdyb3VwPXR5cGUpKSArCiAgZ2VvbV90ZXh0KGFlcyh0eXBlLCB5PTAuMDAyLCBsYWJlbD1wYXN0ZTAoIkNvcnJlbGF0aW9uPSIsQ29ycmVsYXRpb24yLCBncm91cD10eXBlKSkpICsKICAjZ2VvbV90ZXh0KGRhdGE9Z2VuLmdlby5kaXN0LkxpbmVhZ2VbZ2VuLmdlby5kaXN0LkxpbmVhZ2UkdHlwZT09IlJlYWwiLF0sIGFlcyh0eXBlLCB5PTAuMDAyLCBsYWJlbD1wYXN0ZTAoInA8Iixyb3VuZChnZW4uZ2VvLmRpc3QuTGluZWFnZSRwdmFsWzFdLDUpKSksIGluaGVyaXQuYWVzID0gRikgKwogICNnZW9tX3RleHQoZGF0YT1nZW4uZ2VvLmRpc3QuTGluZWFnZVtnZW4uZ2VvLmRpc3QuTGluZWFnZSR0eXBlPT0iUmVhbCIsXSwgYWVzKHR5cGUsIHk9MC4wMDUsIGxhYmVsPXBhc3RlMCgiQ29ycmVsYXRpb249Iixyb3VuZChnZW4uZ2VvLmRpc3QuTGluZWFnZSRDb3JyZWxhdGlvblsxXSw1KSkpLCBpbmhlcml0LmFlcyA9IEYpICsKICBOVUxMCgpgYGAKClNvIGxvb2tpbmcgYXQgdGhlIGZ1bGwgZGF0YXNldApgYGB7cn0KIyBBY2Nyb3NzIHdob2xlIGRhdGFzZXQKQ29ycmVsYXRpb24uZ2VuLnYuZ2VvLmRpc3QuYWxsLnNhbXBsZXMgPC0gY2FsY3VsYXRlLmdlbmV0aWMudnMuZ2VvZ3JhcGhpYy5kaXN0YW5jZS5jb3JyZWxhdGlvbihUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEyKQpDb3JyZWxhdGlvbi5nZW4udi5nZW8uZGlzdC5hbGwuc2FtcGxlc1sxLF0KCiMgQWNjcm9zcyB3aG9sZSBkYXRhc2V0LCBidXQgY29uc3RyYWluZWQgdG8gZ2VuZXRpYyBkaXN0YW5jZXMgd2l0aGluIGxpbmVhZ2UKQ29ycmVsYXRpb24uZ2VuLnYuZ2VvLmRpc3QuYWxsLnNhbXBsZXMuTGluZWFnZSA8LSBjYWxjdWxhdGUuZ2VuZXRpYy52cy5nZW9ncmFwaGljLmRpc3RhbmNlLmNvcnJlbGF0aW9uKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YTJbVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhMiRzYW1lLlRQQS5tYWpvcmxpbmVhZ2U9PSJzYW1lIixdKQpDb3JyZWxhdGlvbi5nZW4udi5nZW8uZGlzdC5hbGwuc2FtcGxlcy5MaW5lYWdlWzEsXQoKIyBFeHBsaWNpdGx5IEJ5IExpbmVhZ2UKQ29ycmVsYXRpb24uZ2VuLnYuZ2VvLmRpc3QuTmljaG9scy5MaW5lYWdlIDwtIGNhbGN1bGF0ZS5nZW5ldGljLnZzLmdlb2dyYXBoaWMuZGlzdGFuY2UuY29ycmVsYXRpb24oVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhMlsoVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhMiRzYW1lLlRQQS5tYWpvcmxpbmVhZ2U9PSJzYW1lIiAmIFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YTIkVFBBX0xpbmVhZ2UudDE9PSJOaWNob2xzIiksXSkKQ29ycmVsYXRpb24uZ2VuLnYuZ2VvLmRpc3QuTmljaG9scy5MaW5lYWdlWzEsXQoKQ29ycmVsYXRpb24uZ2VuLnYuZ2VvLmRpc3QuU1MxNC5MaW5lYWdlIDwtIGNhbGN1bGF0ZS5nZW5ldGljLnZzLmdlb2dyYXBoaWMuZGlzdGFuY2UuY29ycmVsYXRpb24oVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhMlsoVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhMiRzYW1lLlRQQS5tYWpvcmxpbmVhZ2U9PSJzYW1lIiAmIFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YTIkVFBBX0xpbmVhZ2UudDE9PSJTUzE0IiksXSkKQ29ycmVsYXRpb24uZ2VuLnYuZ2VvLmRpc3QuU1MxNC5MaW5lYWdlWzEsXQoKCmBgYAoKCgoKTm93IGRvIGl0IHdpdGhpbiBtYWpvciBzdWJsaW5lYWdlcykKYGBge3J9Cm15LmNvcnJlbGF0aW9uLnN1Ymxpbi5vdXQgPC0gTlVMTApmb3IgKHN1YmxpbiBpbiBjKDEsMiw4LDE0KSkgewogIG15LmNvcnJlbGF0aW9uMSA8LSBjYWxjdWxhdGUuZ2VuZXRpYy52cy5nZW9ncmFwaGljLmRpc3RhbmNlLmNvcnJlbGF0aW9uKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YTJbKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YTIkc2FtZS5UUEEuUGluZWNvbmUuY2x1c3Rlcj09InNhbWUiICYgVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhMiRUUEEucGluZWNvbmUuc3VibGluZWFnZS50MT09c3VibGluKSxdKQogIG15LmNvcnJlbGF0aW9uMSRzdWJsaW5lYWdlIDwtIHN1YmxpbgogIG15LmNvcnJlbGF0aW9uLnN1Ymxpbi5vdXQgPC0gcmJpbmQobXkuY29ycmVsYXRpb24uc3VibGluLm91dCxteS5jb3JyZWxhdGlvbjEpCn0KCm15LmNvcnJlbGF0aW9uLnN1Ymxpbi5vdXRbbXkuY29ycmVsYXRpb24uc3VibGluLm91dCR0eXBlPT0iUmVhbCIsXQoKbXkuY29ycmVsYXRpb24uc3VibGluLm91dC5jb3IucGxvdCA8LSBnZ3Bsb3QobXkuY29ycmVsYXRpb24uc3VibGluLm91dCwgYWVzKHR5cGUsIENvcnJlbGF0aW9uLCBjb2xvcj10eXBlKSkgKyAKICBnZW9tX2JveHBsb3QoKSArIAogIHRoZW1lX2xpZ2h0KCkgKwogICNzY2FsZV95X2xvZzEwKCkgKwogIGZhY2V0X3dyYXAodmFycyhzdWJsaW5lYWdlKSkgKwogICNnZW9tX3RleHQoYWVzKHR5cGUsIHk9MC4wMDIsIGxhYmVsPXBhc3RlMCgicDwiLHJvdW5kKHB2YWxbMV0sNSkpLCBncm91cD10eXBlKSkgKwogIGdlb21fdGV4dChhZXModHlwZSwgeT0wLjAyLCBsYWJlbD1wYXN0ZTAoIkNvcnJlbGF0aW9uOiAiLHJvdW5kKENvcnJlbGF0aW9uMiw1KSksIGdyb3VwPXR5cGUpKSArCiMgIGdlb21fdGV4dChhZXModHlwZSwgeT0wLjAwMSwgbGFiZWw9cGFzdGUwKCJwPCIscm91bmQobXkuY29ycmVsYXRpb24uc3VibGluLm91dCRwdmFsWzFdLDUpKSksIGluaGVyaXQuYWVzID0gRikgKwojICBnZW9tX3RleHQoZGF0YT1teS5jb3JyZWxhdGlvbi5zdWJsaW4ub3V0W215LmNvcnJlbGF0aW9uLnN1Ymxpbi5vdXQkdHlwZT09IlJlYWwiLF0sIGFlcyh0eXBlLCB5PTAuMDA1LCBsYWJlbD1wYXN0ZTAoIkNvcnJlbGF0aW9uPSIscm91bmQobXkuY29ycmVsYXRpb24uc3VibGluLm91dCRDb3JyZWxhdGlvblsxXSw1KSkpLCBpbmhlcml0LmFlcyA9IEYpICsKIyAgZ2VvbV90ZXh0KGRhdGE9bXkuY29ycmVsYXRpb24uc3VibGluLm91dFtteS5jb3JyZWxhdGlvbi5zdWJsaW4ub3V0JHR5cGU9PSJSZWFsIixdLCBhZXModHlwZSwgeT0wLjAwMSwgbGFiZWw9cGFzdGUwKCJwPCIscm91bmQobXkuY29ycmVsYXRpb24uc3VibGluLm91dCRwdmFsWzFdLDUpKSksIGluaGVyaXQuYWVzID0gRikgKwogIHRoZW1lLnRleHQuc2l6ZSArIHRoZW1lKGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC43NSwibGluZSIpKSArCiAgdGhlbWUoc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPSd3aGl0ZScsbGluZXR5cGU9InNvbGlkIiksIHN0cmlwLnRleHQueD1lbGVtZW50X3RleHQoY29sb3I9ImdyZXkyNSIsIHNpemU9MTApLCBzdHJpcC50ZXh0Lnk9ZWxlbWVudF90ZXh0KGNvbG9yPSJncmV5MjUiLCBzaXplPTEwKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIikgKwogIGdndGl0bGUoIkNvcnJlbGF0aW9uIG9mIFBhaXJ3aXNlIGdlbmV0aWMgYW5kIGdlb2dyYXBoaWNhbCBkaXN0YW5jZSB3aXRoaW4gbWFqb3Igc3VibGluZWFnZXMiKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkKCm15LmNvcnJlbGF0aW9uLnN1Ymxpbi5vdXQuY29yLnBsb3QgCgpgYGAKCgoKCgoKYGBge3J9CiMgR2VuZXRpYyBEaXN0YW5jZSB2LnMuIEdlb2dyYXBoaWMgRGlzdGFuY2UgKHNhbWUgc3VibGluZWFnZXMpClRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YTIkVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UudDEgPC0gZmFjdG9yKFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YTIkVFBBLnBpbmVjb25lLnN1YmxpbmVhZ2UudDEsIGxldmVscz1zdWJsaW5lYWdlcy5jb2xzLmJyZXckc3VibGluZWFnZSkKCgpzdWJsaW5lYWdlX25hbWVzIDwtIGMoYDFgPSJTdWJsaW5lYWdlIDEiLGAyYD0iU3VibGluZWFnZSAyIixgOGA9IlN1YmxpbmVhZ2UgOCIsYDE0YD0iU3VibGluZWFnZSAxNCIpCgoKcC5nZW9ncmFwaGljLnZzLmdlbmV0aWMuZGlzdGFuY2UuaGV4LnN1YmxpbiA8LSBnZ3Bsb3QoVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhMlsoVFBBLmFsaWdubWVudC5kYXRhLmRpc3QubWVsdC5tZXRhMiRzYW1lLlRQQS5QaW5lY29uZS5jbHVzdGVyPT0ic2FtZSIgJiBUUEEuYWxpZ25tZW50LmRhdGEuZGlzdC5tZWx0Lm1ldGEyJFRQQS5waW5lY29uZS5zdWJsaW5lYWdlLnQxICVpbiUgYygxLDIsOCwxNCkpLF0sIGFlcyhHZW9ncmFwaGljLkRpc3RhbmNlLERpc3RhbmNlKSkgKwojZ2dwbG90KFRQQS5hbGlnbm1lbnQuZGF0YS5kaXN0Lm1lbHQubWV0YTIsIGFlcyhHZW9ncmFwaGljLkRpc3RhbmNlLERpc3RhbmNlKSkgKyAKICBzdGF0X2Jpbl9oZXgoY29sb3VyPSJ3aGl0ZSIsIG5hLnJtPVRSVUUsIGJpbnMgPSAyMCkgKwogICNnZW9tX2RlbnNpdHlfMmRfZmlsbGVkKCkgKyBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlPSJQdVJkIikgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG91cnM9YygicHVycGxlIiwiZ3JlZW4iKSwgCiAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJDb21wYXJpc29uIEZyZXF1ZW5jeSIsIGJyZWFrcz1jKDMsMTAwLDMwMDApLAogICAgICAgICAgICAgICAgICAgICAgIG5hLnZhbHVlPU5BLCB0cmFucz0ibG9nMTAiKSArIAogIHRoZW1lX2xpZ2h0KCkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKDAsMjUwLDEwKSkgKwogIGxhYnMoeT0iUGFpcndpc2UgZ2VuZXRpYyBkaXN0YW5jZSAoU05QcykiLCB4PSJQYWlyd2lzZSBnZW9ncmFwaGljIGRpc3RhbmNlIChraWxvbWV0ZXJzKSIpICsKICB0aGVtZS50ZXh0LnNpemUgKyB0aGVtZShsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNzUsImxpbmUiKSkgKwogIHRoZW1lKHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0nd2hpdGUnLGxpbmV0eXBlPSJzb2xpZCIpLCBzdHJpcC50ZXh0Lng9ZWxlbWVudF90ZXh0KGNvbG9yPSJncmV5MjUiLCBzaXplPTEwKSwgc3RyaXAudGV4dC55PWVsZW1lbnRfdGV4dChjb2xvcj0iZ3JleTI1Iiwgc2l6ZT0xMCkpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIpICsKICAjZ2d0aXRsZSgiUGFpcndpc2UgU05QcyAoc2FtZSBzdWJsaW5lYWdlKSBhbmQgWWVhcnMgd2l0aGluIGFuZCBiZXR3ZWVuIEJyaXRpc2ggQ29sdW1iaWEgKENhbmFkYSkgYW5kIEVuZ2xhbmQgKFVLKSIpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKSArCiAgZmFjZXRfd3JhcCh2YXJzKFRQQS5waW5lY29uZS5zdWJsaW5lYWdlLnQxKSwgbGFiZWxsZXI9YXNfbGFiZWxsZXIoc3VibGluZWFnZV9uYW1lcykpICsKICBzdGF0X3Ntb290aChtZXRob2Q9J2xtJywgZnVsbHJhbmdlPUYsc2U9VCwgY29sb3I9J2JsYWNrJywgbGV2ZWw9OTUpICsKICBOVUxMCgoKcC5nZW9ncmFwaGljLnZzLmdlbmV0aWMuZGlzdGFuY2UuaGV4LnN1YmxpbiAKCgoKYGBgCgpDb21iaW5lIGxpbmVhZ2UgYW5kIHN1YmxpbmVhZ2UgZGlzdGFuY2UgcGxvdHMKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTgsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBsb3QuZ2VvZ3JhcGhpYy5kaXN0YW5jZS53aXRoaW4uTGluLlN1YmxpbiA8LSBwbG90X2dyaWQocC5nZW9ncmFwaGljLnZzLmdlbmV0aWMuZGlzdGFuY2UuaGV4LkxpbmVhZ2UsIHAuZ2VvZ3JhcGhpYy52cy5nZW5ldGljLmRpc3RhbmNlLmhleC5zdWJsaW4gKyB0aGVtZShsZWdlbmQucG9zaXRpb249J25vbmUnKSwgbmNvbD0xLCByZWxfaGVpZ2h0cz1jKDMsNCksIGxhYmVscz1jKCdBJywnQicpLCBsYWJlbF9zaXplPTExKSAKCgojQ2Fpcm86OkNhaXJvKGZpbGU9cGFzdGUwKEZpZ3VyZV9vdXRwdXRfZGlyZWN0b3J5LCAiU3VwcGxlbWVudGFyeV9GaWd1cmUxMl9HZW5ldGljLXZzLUdlb2dyYXBoaWNfZGlzdGFuY2VfXzAyLTIwMjEuc3ZnIiksIHdpZHRoID0gNjAwLCBoZWlnaHQgPSA2MDAsdHlwZT0ic3ZnIix1bml0cyA9ICJwdCIpCnBsb3QuZ2VvZ3JhcGhpYy5kaXN0YW5jZS53aXRoaW4uTGluLlN1YmxpbgojZGV2Lm9mZigpCgpgYGAKCiMgQ3JlYXRlIFN1cHBsZW1lbnRhcnkgTWV0YWRhdGEgb3V0cHV0IGZpbGUKCmBgYHtyfQojY29sbmFtZXMoVFBBLm1ldGExLjIpClRQQS5tZXRhMS4yLmZpbmFsLlN1cHBsZW1lbnRhcnkgPC0gVFBBLm1ldGExLjJbLGMoIlNhbXBsZV9OYW1lIiwgIlNhbmdlcl9MYW5lX0lEX3JhdyIsICJDbGVhbmVkX2Zhc3RxX2lkIiwgIkNsZWFuZWRfZmFzdHFfcmVhZGNvdW50IiwiU1JSL0VOQV9BY2Nlc3Npb24iLCJSZWFkc19vcl9hc3NlbWJsaWVzIiwiU3BlY2llcyIsIlNhbXBsZV9ZZWFyIiwiQ2l0YXRpb24iLCJTYW1wbGVfVHlwZSIsIkNsaW5pY2FsIiwiRGlyZWN0X2Zyb21fY2xpbiIsIkR1cGxpY2F0ZSIsIkdlb19SZWdpb24iLCJHZW9fQ291bnRyeSIsIkNvbnRpbmVudCIsIlRQQV9MaW5lYWdlIiwiUHJvcG9ydGlvbi1OXz41X21hcHBpbmcrbWFza2luZ19OaWNob2xzIiwiTWFwcGluZ19Hb29kPDI1JU4iLCJNYXBwaW5nX1RlcnJpYmxlPjc1JU4iLCJNZWFuX21hcHBpbmdfY292ZXJhZ2UiKV0KCiMgQXBlbmQgaW5mbyBhYm91dCB3aGljaCBzYW1wbGVzIHdlcmUgdXNlZCBpbiB0aGUgZmluZXNjYWxlIGNsdXN0ZXJpbmcgYW5hbHlzaXMKI2NvbG5hbWVzKFRQQS5tZXRhMS4yLnBpbmVjb25lKQpUUEEubWV0YTEuMi5maW5hbC5TdXBwbGVtZW50YXJ5IDwtIHBseXI6OmpvaW4oVFBBLm1ldGExLjIuZmluYWwuU3VwcGxlbWVudGFyeSxUUEEubWV0YTEuMi5waW5lY29uZVssYygiU2FtcGxlX05hbWUiLCJUUEEucGluZWNvbmUuc3VibGluZWFnZSIpXSwgYnk9IlNhbXBsZV9OYW1lIiwgdHlwZT0iZnVsbCIpClRQQS5tZXRhMS4yLmZpbmFsLlN1cHBsZW1lbnRhcnkkZmluZXNjYWxlLmFuYWx5c2lzIDwtIGlmZWxzZShpcy5uYShUUEEubWV0YTEuMi5maW5hbC5TdXBwbGVtZW50YXJ5JFRQQS5waW5lY29uZS5zdWJsaW5lYWdlKSwiTm8iLCJZZXMiKQoKIyBBcHBlbmQgaW5mbyBhYm91dCB3aGljaCBzYW1wbGVzIHdlcmUgdXNlZCBpbiB0aGUgdGVtcG9yYWwgQkVBU1QgYW5hbHlzaXMKaW4uYmVhc3QudHJlZSA8LSBkYXRhLmZyYW1lKFNhbXBsZV9OYW1lPWZ1bGwuYmVhc3QyLnRpcG5hbWVzJG1ldGEubmFtZSxzdHJpbmdzQXNGYWN0b3JzPUYpCmluLmJlYXN0LnRyZWUkZnVsbC50ZW1wb3JhbC5hbmFseXNpcyA8LSAiWWVzIgpUUEEubWV0YTEuMi5maW5hbC5TdXBwbGVtZW50YXJ5IDwtIHBseXI6OmpvaW4oVFBBLm1ldGExLjIuZmluYWwuU3VwcGxlbWVudGFyeSwgaW4uYmVhc3QudHJlZSwgYnk9IlNhbXBsZV9OYW1lIiwgdHlwZT0iZnVsbCIpClRQQS5tZXRhMS4yLmZpbmFsLlN1cHBsZW1lbnRhcnkkZnVsbC50ZW1wb3JhbC5hbmFseXNpcyA8LSBpZmVsc2UoaXMubmEoVFBBLm1ldGExLjIuZmluYWwuU3VwcGxlbWVudGFyeSRmdWxsLnRlbXBvcmFsLmFuYWx5c2lzKSwiTm8iLCJZZXMiKQoKIyBBcHBlbmQgYW50aW1pY3JvYmlhbCByZXNpc3RhbmNlIGluZm9ybWF0aW9uClRQQS5tZXRhMS4yLmZpbmFsLlN1cHBsZW1lbnRhcnkgPC0gcGx5cjo6am9pbihUUEEubWV0YTEuMi5maW5hbC5TdXBwbGVtZW50YXJ5LCBkYXRhLmZyYW1lKFNhbXBsZV9OYW1lPVRQQS5nbG9iYWwuY29tcG1hcHBpbmcuMjNzJFNhbXBsZSwgQTIwNThHPVRQQS5nbG9iYWwuY29tcG1hcHBpbmcuMjNzJFZhcmlhbnRQcmVzZW50X0EyMDU4R19yZWRvLCBBMjA1OUc9VFBBLmdsb2JhbC5jb21wbWFwcGluZy4yM3MkVmFyaWFudFByZXNlbnRfQTIwNTlHX3JlZG8sIHN0cmluZ3NBc0ZhY3RvcnM9RiksIGJ5PSJTYW1wbGVfTmFtZSIsIHR5cGU9ImZ1bGwiKQoKIyBSZWxhYmVsIGNpdGF0aW9uIGZvciBub3ZlbCBzZXF1ZW5jZXMKClRQQS5tZXRhMS4yLmZpbmFsLlN1cHBsZW1lbnRhcnlbVFBBLm1ldGExLjIuZmluYWwuU3VwcGxlbWVudGFyeSRDaXRhdGlvbj09InVucHVibGlzaGVkLVdTSSIsIkNpdGF0aW9uIl0gPC0gIlRoaXNfU3R1ZHkiClRQQS5tZXRhMS4yLmZpbmFsLlN1cHBsZW1lbnRhcnlbVFBBLm1ldGExLjIuZmluYWwuU3VwcGxlbWVudGFyeSRDaXRhdGlvbj09InVucHVibGlzaGVkLVRhaWFyb2EiLCJDaXRhdGlvbiJdIDwtICJUaGlzX1N0dWR5IgoKCiMgUmVvcmRlciBkYXRhZnJhbWUgYnkgQ2l0YXRpb24KVFBBLm1ldGExLjIuZmluYWwuU3VwcGxlbWVudGFyeSA8LSBUUEEubWV0YTEuMi5maW5hbC5TdXBwbGVtZW50YXJ5W29yZGVyKFRQQS5tZXRhMS4yLmZpbmFsLlN1cHBsZW1lbnRhcnkkQ2l0YXRpb24sVFBBLm1ldGExLjIuZmluYWwuU3VwcGxlbWVudGFyeSRTYW1wbGVfTmFtZSksXQoKCiN3cml0ZS5jc3YoVFBBLm1ldGExLjIuZmluYWwuU3VwcGxlbWVudGFyeSwgZmlsZT1wYXN0ZTAoRmlndXJlX291dHB1dF9kaXJlY3RvcnksICJTdXBwbGVtZW50YXJ5X0RhdGExX1NhbXBsZS1NZXRhZGF0YV9fMDMtMjAyMS5jc3YiKSwgcm93Lm5hbWVzID0gRikKCmBgYAoKCkVOQSBhc3NlbWJseSBzdWJtaXNzaW9ucyAoaGlnaCBxdWFsaXR5IGFzc2VtYmxpZXMgLSBhc3NlbWJsaWVzIG5vdCBhY3R1YWxseSB1c2VkIGZvciBwYXBlciwgYnV0IHdpbGwgcHVibGlzaCBzZXBhcmF0ZWx5IGZvciB0aGUgY29tbXVuaXR5KQpgYGB7cn0KCiNFTkEuYXNzZW1ibGllcyA8LSBUUEEubWV0YTEuMlsoVFBBLm1ldGExLjIkYENoZWNrTT45NSVfQ29tcGxldGVuZXNzYD09J3llcycgJiBUUEEubWV0YTEuMiRgQ2hlY2tNPDUlLWNvbnRhbWluYXRpb25gPT0neWVzJyAmIFRQQS5tZXRhMS4yJGBjb250aWdzXzw2MDBgPT0neWVzJyAmIFRQQS5tZXRhMS4yJGBNYXBwaW5nX0dvb2Q8MjUlTmA9PSdZZXMnICYgVFBBLm1ldGExLjIkQ2l0YXRpb249PSJ1bnB1Ymxpc2hlZC1XU0kiKSxjKCJTYW1wbGVfTmFtZSIsICJTYW5nZXJfTGFuZV9JRF9yYXciLCAiQ2xlYW5lZF9mYXN0cV9pZCIsICJDbGVhbmVkX2Zhc3RxX3JlYWRjb3VudCIsIlNSUi9FTkFfQWNjZXNzaW9uIiwiUmVhZHNfb3JfYXNzZW1ibGllcyIsIlNwZWNpZXMiLCJTYW1wbGVfWWVhciIsIkNpdGF0aW9uIiwiU2FtcGxlX1R5cGUiLCJDbGluaWNhbCIsIkRpcmVjdF9mcm9tX2NsaW4iLCJEdXBsaWNhdGUiLCJHZW9fUmVnaW9uIiwiR2VvX0NvdW50cnkiLCJDb250aW5lbnQiLCJUUEFfTGluZWFnZSIsIlByb3BvcnRpb24tTl8+NV9tYXBwaW5nK21hc2tpbmdfTmljaG9scyIsIk1hcHBpbmdfR29vZDwyNSVOIiwiTWFwcGluZ19UZXJyaWJsZT43NSVOIiwiTWVhbl9tYXBwaW5nX2NvdmVyYWdlIiwiU1BBZGVzLXBpbG9uX2Fzc2VtYmx5X2lkIiwiQXNzZW1ibHlfI19jb250aWdzIiwiQXNzZW1ibHlfTjUwIiwiQ2hlY2tNLWNvbXBsZXRlbmVzcyIsIkNoZWNrTS1jb250YW1pbmF0aW9uIildCgoKI0VOQS5hc3NlbWJsaWVzIDwtIEVOQS5hc3NlbWJsaWVzW0VOQS5hc3NlbWJsaWVzJGBBc3NlbWJseV8jX2NvbnRpZ3NgPDI1MCxdCiNFTkEuYXNzZW1ibGllcyA8LSBFTkEuYXNzZW1ibGllc1tFTkEuYXNzZW1ibGllcyRgQ2hlY2tNLWNvbnRhbWluYXRpb25gPDIuNSxdCiNFTkEuYXNzZW1ibGllcyA8LSBFTkEuYXNzZW1ibGllc1shaXMubmEoRU5BLmFzc2VtYmxpZXMkU2FtcGxlX05hbWUpLF0KCgpjKCJOTDEyIiwgIlBIRTEyMDAwNkEiLCAiUEhFMTIwMDA3QSIsICJQSEUxMjAwMDlCIiwgIlBIRTEyMDAxMUEiLCAiUEhFMTIwMDIxQSIsICJQSEUxMjAwMjRBIiwgIlBIRTEzMDAzNkEiLCAiUEhFMTMwMDM5QSIsICJQSEUxMzAwNDBBIiwgIlBIRTEzMDA0M0EiLCAiUEhFMTMwMDQ1QSIsICJQSEUxMzAwNDdBIiwgIlBIRTEzMDA1MkEiLCAiUEhFMTMwMDUzQSIsICJQSEUxMzAwNjRBIiwgIlBIRTE0MDA3M0EiLCAiUEhFMTQwMDc0QSIsICJQSEUxNDAwODRBIiwgIlBIRTE0MDA4NUEiLCAiUEhFMTQwMDkzQSIsICJQSEUxNDAwOTVBIiwgIlBIRTE1MDExMEEiLCAiUEhFMTUwMTE5QSIsICJQSEUxNTAxMjFBIiwgIlBIRTE1MDEyMkEiLCAiUEhFMTUwMTI2QSIsICJQSEUxNTAxMzBBIiwgIlBIRTE1MDEzMUEiLCAiUEhFMTUwMTMzQSIsICJQSEUxNTAxMzdBIiwgIlBIRTE1MDEzOEEiLCAiUEhFMTUwMTQzQSIsICJQSEUxNTAxNDVBIiwgIlBIRTE1MDE0OEEiLCAiUEhFMTUwMTQ5QSIsICJQSEUxNTAxNTNBIiwgIlBIRTE1MDE2MEEiLCAiUEhFMTUwMTYxQSIsICJQSEUxNTAxNjJBIiwgIlBIRTE1MDE2NkEiLCAiUEhFMTUwMTc3QSIsICJQSEUxNjAxOTBBIiwgIlBIRTE2MDE5NkEiLCAiUEhFMTYwMTk3QSIsICJQSEUxNjAxOThBIiwgIlBIRTE2MDIwM0EiLCAiUEhFMTYwMjExQSIsICJQSEUxNjAyMTRBIiwgIlBIRTE2MDIxN0EiLCAiUEhFMTYwMjI0QSIsICJQSEUxNjAyMzlBIiwgIlBIRTE2MDI0MEEiLCAiUEhFMTYwMjQzQSIsICJQSEUxNjAyNDlBIiwgIlBIRTE2MDI1M0EiLCAiUEhFMTYwMjU2QSIsICJQSEUxNjAyNTlBIiwgIlBIRTE2MDI2MkEiLCAiUEhFMTYwMjY0QSIsICJQSEUxNjAyNzdBIiwgIlBIRTE2MDI4MEEiLCAiUEhFMTYwMjg3QSIsICJQSEUxNjAyOTBBIiwgIlBIRTE2MDI5OEEiLCAiUEhFMTYwMjk5QSIsICJQSEUxNjAzMDlBIiwgIlBIRTE2MDMxMkEiLCAiUEhFMTYwMzE1QSIsICJQSEUxNjAzMTZBIiwgIlBIRTE3MDMyOEEiLCAiUEhFMTcwMzI5QSIsICJQSEUxNzAzMzNBIiwgIlBIRTE3MDMzNkIiLCAiUEhFMTcwMzQ2QSIsICJQSEUxNzAzNDlBIiwgIlBIRTE3MDM1MUEiLCAiUEhFMTcwMzUyQSIsICJQSEUxNzAzNTZBIiwgIlBIRTE3MDM2NkEiLCAiUEhFMTcwMzcwQSIsICJQSEUxNzAzNzJBIiwgIlBIRTE3MDM3NEEiLCAiUEhFMTcwMzgwQSIsICJQSEUxNzAzODFBIiwgIlBIRTE3MDM4N0EiLCAiUEhFMTcwMzg4QSIsICJQSEUxNzAzOThBIiwgIlBIRTE3MDQwMkEiLCAiUEhFMTcwNDAzQSIsICJQSEUxNzA0MDVBIiwgIlBIRTE3MDQwN0EiLCAiUEhFMTcwNDA4QSIsICJUUEFfQUxDMDE1IiwgIlRQQV9BTEMwMzQiLCAiVFBBX0FMQzA3NyIsICJUUEFfQkNDMDA0IiwgIlRQQV9CQ0MwMDUiLCAiVFBBX0JDQzAwOCIsICJUUEFfQkNDMDA5IiwgIlRQQV9CQ0MwMTIiLCAiVFBBX0JDQzAxNCIsICJUUEFfQkNDMDIzIiwgIlRQQV9CQ0MwMzAiLCAiVFBBX0JDQzAzMiIsICJUUEFfQkNDMDM0IiwgIlRQQV9CQ0MwNDAiLCAiVFBBX0JDQzA0OSIsICJUUEFfQkNDMDUyIiwgIlRQQV9CQ0MwNTUiLCAiVFBBX0JDQzA1OCIsICJUUEFfQkNDMDYxIiwgIlRQQV9CQ0MwNjMiLCAiVFBBX0JDQzA2NCIsICJUUEFfQkNDMDc1IiwgIlRQQV9CQ0MwNzkiLCAiVFBBX0JDQzA4NSIsICJUUEFfQkNDMDg4IiwgIlRQQV9CQ0MxMDEiLCAiVFBBX0JDQzEwMiIsICJUUEFfQkNDMTA2IiwgIlRQQV9CQ0MxMDgiLCAiVFBBX0JDQzEwOSIsICJUUEFfQkNDMTExIiwgIlRQQV9CQ0MxMjIiLCAiVFBBX0JDQzEyNyIsICJUUEFfQkNDMTI4IiwgIlRQQV9CQ0MxMjkiLCAiVFBBX0JDQzEzMCIsICJUUEFfQkNDMTMyIiwgIlRQQV9CQ0MxMzQiLCAiVFBBX0JDQzEzNyIsICJUUEFfQkNDMTM5IiwgIlRQQV9CQ0MxNDAiLCAiVFBBX0JDQzE0MSIsICJUUEFfcmVCQ0MxNjUiLCAiVFBBX0JDQzE2NiIsICJUUEFfQkNDMTc0IiwgIlRQQV9CQ0MxNzUiLCAiVFBBX0JDQzE4MSIsICJUUEFfQkNDMTg1IiwgIlRQQV9CQ0MxODYiLCAiVFBBX0JDQzE4NyIsICJUUEFfQkNDMTk2IiwgIlRQQV9CQ0MxOTciLCAiVFBBX0JDQzE5OCIsICJUUEFfQkNDMTk5IiwgIlRQQV9FSVIwMDgiLCAiVFBBX0VJUjAxMyIsICJUUEFfRUlSMDE1IiwgIlRQQV9FSVIwMTciLCAiVFBBX0VTQkNOMDA1IiwgIlRQQV9PTUkwMDIiLCAiVFBBX09NSTAxNSIsICJUUEFfT01JMDIxIiwgIlRQQV9PTUkwNzUiLCAiVFBBX1VLQklSMDI2IiwgIlRQQV9VS0JJUjAyOCIsICJUUEFfVUtCSVIwNDQiLCAiVFBBX1VLQklSMDUyIiwgIlRQQV9VS0JSRzAwNCIsICJUUEFfVUtCUkcwMDgiLCAiVFBBX1VLQlJHMDEwIiwgIlRQQV9VS0JSRzAxMiIsICJUUEFfVUtCUkcwMTciLCAiVFBBX1VLQlJHMDE4IiwgIlRQQV9VS0xFRTAwNCIsICJUUEFfVUtNQU4wMDMiLCAiVFBBX1VLTUFOMDE5IiwgIlRQQV9VS01BTjAyNyIsICJUUEFfVUtNQU4wNDciLCAiVFBBX1VLTUFOMDU0IiwgIlRQQV9VU0wtQkFMLTIiLCAiVFBBX1VTTC1CQUwtNiIsICJUUEFfVVNMLUJBTC03IiwgIlRQQV9VU0wtQkFMLTgiLCAiVFBBX1VTTC1HcmFkeS0xIiwgIlRQQV9VU0wtSGFpdGktQiIsICJUUEFfVVNMLVBoaWwtMSIsICJUUEFfVVNMLVBoaWwtMyIsICJUUEFfVVNMLVNFQS04MS0zIiwgIlRQQV9VU0wtU0VBLTgxLTgiLCAiVFBBX1VTTC1TRUEtODMtMSIsICJUUEFfVVNMLVNFQS04My0yIiwgIlRQQV9VU0wtU0VBLTg0LTIiLCAiVFBBX1VTTC1TRUEtODYtMSIsICJUUEFfVVNMLVNFQS04Ny0xIiwgIlRQQV9aSU0wMDUiLCAiVFBBX1pJTTAwNyIsICJUUEFfWklNMDE4IiwgIlRQQV9aSU0wMjQiLCAiVFBBX1pJTTAyNSIsICJUUEFfWklNMDI4IiwgIlVXMjAyQiIsICJUUEFfQUxDMTA1IiwgIlRQQV9CQ0MxMDMiLCAiVFBBX09NSTAwNiIsICJUUEFfT01JMDIyIiwgIlRQQV9PTUkwMjkiLCAiVFBBX09NSTAzMyIsICJUUEFfWklNMDE5IiwgIlRQQV9IVU4xOTAwMjIiLCAiVFBBX0hVTjIwMDAyNCIsICJUUEFfSFVOMTkwMDIwIiwgIlRQQV9SVVNfVHV2YS0zOSIsICJUUEFfUlVTX1R1dmEtNTgiLCAiVFBBX1JVU19UdXZhLTU5IiwgIlRQQV9SVVNfVHV2YS0yNiIsICJUUEFfUlVTX1R1dmEtNDEiLCAiVFBBX1NXRS05OTYiLCAiVFBBX0FVU0JSLTQxIikKCgpgYGAKCgoK